diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index e2cdfbf14..8032796b4 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -23,6 +23,7 @@ falkon_tests( webviewtest webtabtest sqldatabasetest + sitesettingstest ) set(falkon_autotests_SRCS ${CMAKE_SOURCE_DIR}/tests/modeltest/modeltest.cpp) diff --git a/autotests/sitesettingstest.cpp b/autotests/sitesettingstest.cpp new file mode 100644 index 000000000..c55c5a967 --- /dev/null +++ b/autotests/sitesettingstest.cpp @@ -0,0 +1,111 @@ +/* ============================================================ + * Falkon - Qt web browser + * Copyright (C) 2024 Juraj Oravec + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * ============================================================ */ + +#include "sitesettingstest.h" + +#include "mainapplication.h" +#include "tabbedwebview.h" +#include "webpage.h" + +#include "autotests.h" +#include "tabwidget.h" + + +void SiteSettingsTest::initTestCase() +{ + /* Wait until the initial tab (at index 0) in the window is created */ + QTRY_COMPARE(mApp->getWindow()->tabCount(), 1); +} + +void SiteSettingsTest::cleanupTestCase() +{ +} + +void SiteSettingsTest::webAttributeTest() +{ + SiteSettingsManager *siteSettings = mApp->siteSettingsManager(); + siteSettings->setOption(QWebEngineSettings::AutoLoadImages, QUrl(QSL("https://www.falkon.org/")), SiteSettingsManager::Deny); + siteSettings->setOption(QWebEngineSettings::JavascriptEnabled, QUrl(QSL("https://kde.org/")), SiteSettingsManager::Deny); + siteSettings->setOption(QWebEngineSettings::LocalStorageEnabled, QUrl(QSL("https://store.falkon.org/")), SiteSettingsManager::Deny); + siteSettings->setOption(QWebEngineSettings::PlaybackRequiresUserGesture, QUrl(QSL("https://planet.kde.org/")), SiteSettingsManager::Allow); + + + WebTab tab; + + checkInternalPage(&tab, QUrl(QSL("falkon:start"))); + + checkExternalPage(&tab, QUrl(QSL("https://www.falkon.org/"))); + checkExternalPage(&tab, QUrl(QSL("https://kde.org/"))); + checkExternalPage(&tab, QUrl(QSL("https://store.falkon.org/"))); + + checkInternalPage(&tab, QUrl(QSL("falkon:about"))); + + checkExternalPage(&tab, QUrl(QSL("https://planet.kde.org/"))); +} + +bool SiteSettingsTest::checkWebAttributes(WebPage *page, QHash webAttributes) +{ + for (auto it = webAttributes.begin(); it != webAttributes.end(); ++it) { + if (page->settings()->testAttribute(it.key()) != it.value()) { + return false; + } + } + + return true; +} + +void SiteSettingsTest::checkInternalPage(WebTab *tab, QUrl url) +{ + QMap internalWebAttributes = { + {QWebEngineSettings::AutoLoadImages, true} + ,{QWebEngineSettings::JavascriptEnabled, true} + ,{QWebEngineSettings::JavascriptCanOpenWindows, false} + ,{QWebEngineSettings::JavascriptCanAccessClipboard, true} + ,{QWebEngineSettings::JavascriptCanPaste, false} + ,{QWebEngineSettings::AllowWindowActivationFromJavaScript, false} + ,{QWebEngineSettings::LocalStorageEnabled, true} + ,{QWebEngineSettings::FullScreenSupportEnabled, mApp->webSettings()->testAttribute(QWebEngineSettings::FullScreenSupportEnabled)} + ,{QWebEngineSettings::AllowRunningInsecureContent, false} + ,{QWebEngineSettings::AllowGeolocationOnInsecureOrigins, false} + ,{QWebEngineSettings::PlaybackRequiresUserGesture, mApp->webSettings()->testAttribute(QWebEngineSettings::PlaybackRequiresUserGesture)} + ,{QWebEngineSettings::WebRTCPublicInterfacesOnly, false} + }; + + QSignalSpy spy(tab, SIGNAL(loadingChanged(bool))); + tab->load(url); + QTRY_COMPARE(spy.count(), 3); + + auto *page = tab->webView()->page(); + for (auto it = internalWebAttributes.begin(); it != internalWebAttributes.end(); ++it) { + QCOMPARE(page->settings()->testAttribute(it.key()), it.value()); + } +} + +void SiteSettingsTest::checkExternalPage(WebTab *tab, QUrl url) +{ + SiteSettingsManager *siteSettings = mApp->siteSettingsManager(); + + QSignalSpy spy(tab, SIGNAL(loadingChanged(bool))); + tab->load(url); + QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 3, 20000); + + auto *page = tab->webView()->page(); + QCOMPARE(checkWebAttributes(page, siteSettings->getWebAttributes(url)), true); +} + +FALKONTEST_MAIN(SiteSettingsTest) diff --git a/autotests/sitesettingstest.h b/autotests/sitesettingstest.h new file mode 100644 index 000000000..a8cdb66d3 --- /dev/null +++ b/autotests/sitesettingstest.h @@ -0,0 +1,47 @@ +/* ============================================================ + * Falkon - Qt web browser + * Copyright (C) 2024 Juraj Oravec + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * ============================================================ */ + +#ifndef SITESETTINGSTEST_H +#define SITESETTINGSTEST_H + +#include "sitesettingsmanager.h" + +#include + +class WebPage; +class WebTab; + +class SiteSettingsTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + + void webAttributeTest(); + +private: + bool checkWebAttributes(WebPage *page, QHash webAttributes); + + void checkInternalPage(WebTab *tab, QUrl url); + void checkExternalPage(WebTab *tab, QUrl url); +}; + +#endif // SITESETTINGSTEST_H + diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 4ea872344..faae040a1 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -149,7 +149,9 @@ set(SRCS ${SRCS} other/licenseviewer.cpp other/qzsettings.cpp other/siteinfo.cpp + other/siteinfopermissionitem.cpp other/siteinfowidget.cpp + other/sitesettingsmanager.cpp other/statusbar.cpp other/updater.cpp other/useragentmanager.cpp @@ -208,6 +210,9 @@ set(SRCS ${SRCS} preferences/pluginsmanager.cpp preferences/preferences.cpp preferences/schememanager.cpp + preferences/sitesettingsattributesitem.cpp + preferences/sitesettingsbrowsedialog.cpp + preferences/sitesettingshtml5item.cpp preferences/thememanager.cpp preferences/useragentdialog.cpp session/recoveryjsobject.cpp @@ -242,7 +247,6 @@ set(SRCS ${SRCS} tools/focusselectlineedit.cpp tools/headerview.cpp tools/horizontallistwidget.cpp - tools/html5permissions/html5permissionsdialog.cpp tools/html5permissions/html5permissionsmanager.cpp tools/html5permissions/html5permissionsnotification.cpp tools/iconprovider.cpp @@ -379,7 +383,9 @@ set(SRCS ${SRCS} other/licenseviewer.h other/qzsettings.h other/siteinfo.h + other/siteinfopermissionitem.h other/siteinfowidget.h + other/sitesettingsmanager.h other/statusbar.h other/updater.h other/useragentmanager.h @@ -438,6 +444,9 @@ set(SRCS ${SRCS} preferences/pluginsmanager.h preferences/preferences.h preferences/schememanager.h + preferences/sitesettingsattributesitem.h + preferences/sitesettingsbrowsedialog.h + preferences/sitesettingshtml5item.h preferences/thememanager.h preferences/useragentdialog.h session/recoveryjsobject.h @@ -472,7 +481,6 @@ set(SRCS ${SRCS} tools/focusselectlineedit.h tools/headerview.h tools/horizontallistwidget.h - tools/html5permissions/html5permissionsdialog.h tools/html5permissions/html5permissionsmanager.h tools/html5permissions/html5permissionsnotification.h tools/iconprovider.h @@ -543,6 +551,7 @@ qt_wrap_ui(SRCS other/iconchooser.ui other/protocolhandlerdialog.ui other/siteinfo.ui + other/siteinfopermissionitem.ui other/siteinfowidget.ui preferences/acceptlanguage.ui preferences/addacceptlanguage.ui @@ -552,6 +561,9 @@ qt_wrap_ui(SRCS preferences/pluginslist.ui preferences/preferences.ui preferences/schememanager.ui + preferences/sitesettingsattributesitem.ui + preferences/sitesettingsbrowsedialog.ui + preferences/sitesettingshtml5item.ui preferences/thememanager.ui preferences/useragentdialog.ui session/sessionmanagerdialog.ui @@ -559,7 +571,6 @@ qt_wrap_ui(SRCS sidebar/historysidebar.ui tools/certificateinfowidget.ui tools/docktitlebarwidget.ui - tools/html5permissions/html5permissionsdialog.ui tools/html5permissions/html5permissionsnotification.ui webengine/jsalert.ui webengine/jsconfirm.ui diff --git a/src/lib/app/mainapplication.cpp b/src/lib/app/mainapplication.cpp index 4d0cecd97..802d4628c 100644 --- a/src/lib/app/mainapplication.cpp +++ b/src/lib/app/mainapplication.cpp @@ -42,6 +42,7 @@ #include "searchenginesmanager.h" #include "desktopnotificationsfactory.h" #include "html5permissions/html5permissionsmanager.h" +#include "sitesettingsmanager.h" #include "scripts.h" #include "sessionmanager.h" #include "closedwindowsmanager.h" @@ -105,6 +106,7 @@ MainApplication::MainApplication(int &argc, char** argv) , m_closedWindowsManager(nullptr) , m_protocolHandlerManager(nullptr) , m_html5PermissionsManager(nullptr) + , m_siteSettingsManager(nullptr) , m_desktopNotifications(nullptr) , m_webProfile(nullptr) , m_autoSaver(nullptr) @@ -645,6 +647,14 @@ HTML5PermissionsManager* MainApplication::html5PermissionsManager() return m_html5PermissionsManager; } +SiteSettingsManager * MainApplication::siteSettingsManager() +{ + if (!m_siteSettingsManager) { + m_siteSettingsManager = new SiteSettingsManager(this); + } + return m_siteSettingsManager; +} + DesktopNotificationsFactory* MainApplication::desktopNotifications() { if (!m_desktopNotifications) { @@ -980,6 +990,13 @@ void MainApplication::loadSettings() webSettings->setAttribute(QWebEngineSettings::PdfViewerEnabled, settings.value(QSL("intPDFViewer"), false).toBool()); webSettings->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, settings.value(QSL("screenCaptureEnabled"), false).toBool()); +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 6, 0) + webSettings->setAttribute(QWebEngineSettings::ReadingFromCanvasEnabled, settings.value(QSL("readingFromCanvasEnabled"), false).toBool()); +#endif +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 7, 0) + webSettings->setAttribute(QWebEngineSettings::ForceDarkMode, settings.value(QSL("forceDarkMode"), false).toBool()); +#endif + webSettings->setDefaultTextEncoding(settings.value(QSL("DefaultEncoding"), webSettings->defaultTextEncoding()).toString()); setWheelScrollLines(settings.value(QSL("wheelScrollLines"), wheelScrollLines()).toInt()); diff --git a/src/lib/app/mainapplication.h b/src/lib/app/mainapplication.h index 4003ac65f..87e2d6415 100644 --- a/src/lib/app/mainapplication.h +++ b/src/lib/app/mainapplication.h @@ -53,6 +53,7 @@ class ProxyStyle; class SessionManager; class ClosedWindowsManager; class ProtocolHandlerManager; +class SiteSettingsManager; class FALKON_EXPORT MainApplication : public QtSingleApplication { @@ -111,6 +112,7 @@ public: ClosedWindowsManager* closedWindowsManager(); ProtocolHandlerManager *protocolHandlerManager(); HTML5PermissionsManager* html5PermissionsManager(); + SiteSettingsManager* siteSettingsManager(); DesktopNotificationsFactory* desktopNotifications(); QWebEngineProfile* webProfile() const; QWebEngineSettings *webSettings() const; @@ -188,6 +190,7 @@ private: ClosedWindowsManager* m_closedWindowsManager; ProtocolHandlerManager *m_protocolHandlerManager; HTML5PermissionsManager* m_html5PermissionsManager; + SiteSettingsManager* m_siteSettingsManager; DesktopNotificationsFactory* m_desktopNotifications; QWebEngineProfile* m_webProfile; diff --git a/src/lib/app/profilemanager.cpp b/src/lib/app/profilemanager.cpp index 177876049..dc51c890a 100644 --- a/src/lib/app/profilemanager.cpp +++ b/src/lib/app/profilemanager.cpp @@ -21,6 +21,8 @@ #include "updater.h" #include "qztools.h" #include "sqldatabase.h" +#include "sitesettingsmanager.h" +#include "settings.h" #include #include @@ -29,6 +31,7 @@ #include #include #include +#include #include @@ -89,6 +92,7 @@ void ProfileManager::initCurrentProfile(const QString &profileName) updateCurrentProfile(); connectDatabase(); + updateDatabase(); } int ProfileManager::createProfile(const QString &profileName) @@ -166,10 +170,10 @@ void ProfileManager::updateCurrentProfile() // If file exists, just update the profile to current version if (versionFile.exists()) { versionFile.open(QFile::ReadOnly); - QString profileVersion = QString::fromUtf8(versionFile.readAll()); + profileVersion = QString::fromUtf8(versionFile.readAll()).trimmed(); versionFile.close(); - updateProfile(QString::fromLatin1(Qz::VERSION), profileVersion.trimmed()); + updateProfile(QString::fromLatin1(Qz::VERSION), profileVersion); } else { copyDataToProfile(); @@ -311,3 +315,176 @@ void ProfileManager::connectDatabase() SqlDatabase::instance()->setDatabase(db); } + +void ProfileManager::updateDatabase() +{ + if (QString::fromLatin1(Qz::VERSION) == profileVersion) { + return; + } + + Updater::Version prof(profileVersion); + + /* Profile is from newer version than running application */ + if (prof > Updater::Version(QString::fromLatin1(Qz::VERSION))) { + // Ignore + return; + } + + /* Do not try to update database of too old profile */ + if (prof < Updater::Version(QStringLiteral("1.9.0"))) { + std::cout << "Falkon: Using profile from QupZilla " << qPrintable(profileVersion) << " is not supported!" << std::endl; + return; + } + + /* Update in 24.08.00 */ + if (prof < Updater::Version(QStringLiteral("24.07.70"))) { + std::cout << "Falkon: Updating database to version " << qPrintable(QString::fromLatin1(Qz::VERSION)) << std::endl; + + SqlDatabase::instance()->database().transaction(); + + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare(QStringLiteral( + "CREATE TABLE IF NOT EXISTS site_settings (" + "id INTEGER PRIMARY KEY," + "server TEXT NOT NULL," + + "zoom_level INTEGER DEFAULT -1," + "allow_cookies INTEGER DEFAULT 0," + + "wa_autoload_images INTEGER DEFAULT 0," + "wa_js_enabled INTEGER DEFAULT 0," + "wa_js_open_windows INTEGER DEFAULT 0," + "wa_js_access_clipboard INTEGER DEFAULT 0," + "wa_js_can_paste INTEGER DEFAULT 0," + "wa_js_window_activation INTEGER DEFAULT 0," + "wa_local_storage INTEGER DEFAULT 0," + "wa_fullscreen_support INTEGER DEFAULT 0," + "wa_run_insecure_content INTEGER DEFAULT 0," + "wa_playback_needs_gesture INTEGER DEFAULT 0," + "wa_reading_from_canvas INTEGER DEFAULT 0," + "wa_force_dark_mode INTEGER DEFAULT 0," + + "f_notifications INTEGER DEFAULT 0," + "f_geolocation INTEGER DEFAULT 0," + "f_media_audio_capture INTEGER DEFAULT 0," + "f_media_video_capture INTEGER DEFAULT 0," + "f_media_audio_video_capture INTEGER DEFAULT 0," + "f_mouse_lock INTEGER DEFAULT 0," + "f_desktop_video_capture INTEGER DEFAULT 0," + "f_desktop_audio_video_capture INTEGER DEFAULT 0" + ");" + )); + + if (!query.exec()) { + qCritical() << "Error while creating table 'site_settings' in database: " << query.lastError().text(); + qFatal("ProfileManager::updateDatabase Unable to create table 'site_settings' in the database!"); + } + + query.prepare(QStringLiteral( + "CREATE UNIQUE INDEX IF NOT EXISTS site_settings_server_uniqueindex ON site_settings (server);" + )); + + if (!query.exec()) { + qFatal() << "Error while creating unique index for table 'site_settings': " << query.lastError().text(); + } + + const QHash html5SettingPairs = { + {QWebEnginePage::Notifications, QSL("Notifications")}, + {QWebEnginePage::Geolocation, QSL("Geolocation")}, + {QWebEnginePage::MediaAudioCapture, QSL("MediaAudioCapture")}, + {QWebEnginePage::MediaVideoCapture, QSL("MediaVideoCapture")}, + {QWebEnginePage::MediaAudioVideoCapture, QSL("MediaAudioVideoCapture")}, + {QWebEnginePage::MouseLock, QSL("MouseLock")}, + {QWebEnginePage::DesktopVideoCapture, QSL("DesktopVideoCapture")}, + {QWebEnginePage::DesktopAudioVideoCapture,QSL("DesktopAudioVideoCapture")} + }; + QHash siteSettings; + + Settings settings; + + /* HTML5 permissions */ + settings.beginGroup(QSL("HTML5Notifications")); + + auto loadHtml5Settings = [&](const QString &suflix, const SiteSettingsManager::Permission permission) { + for (auto [feature, settingName] : html5SettingPairs.asKeyValueRange()) { + auto const serverList = settings.value(settingName + suflix, QStringList()).toStringList(); + + for (const auto &server : serverList) { + if (!siteSettings.contains(server)) { + siteSettings[server] = SiteSettingsManager::SiteSettings(); + for (auto [f, nameUnused] : html5SettingPairs.asKeyValueRange()) { + siteSettings[server].features[f] = SiteSettingsManager::Default; + } + } + + siteSettings[server].server = server; + siteSettings[server].features[feature] = permission; + } + } + }; + + loadHtml5Settings(QSL("Granted"), SiteSettingsManager::Allow); + loadHtml5Settings(QSL("Denied"), SiteSettingsManager::Deny); + + settings.endGroup(); + + /* Cookies white/black lists */ + settings.beginGroup(QSL("Cookie-Settings")); + + auto loadCookiesSettings = [&](const QString &listName, const SiteSettingsManager::Permission permission) { + auto const serverList = settings.value(listName, QStringList()).toStringList(); + + for (const auto &server : serverList) { + if (!siteSettings.contains(server)) { + siteSettings[server] = SiteSettingsManager::SiteSettings(); + } + + siteSettings[server].server = server; + siteSettings[server].AllowCookies = permission; + } + }; + + loadCookiesSettings(QSL("whitelist"), SiteSettingsManager::Allow); + loadCookiesSettings(QSL("blacklist"), SiteSettingsManager::Deny); + + settings.endGroup(); + + /* Insert SQL for SiteSettings */ + query.prepare(QSL( + "INSERT INTO site_settings (" + "server," + "allow_cookies," + "f_notifications," + "f_geolocation," + "f_media_audio_capture," + "f_media_video_capture," + "f_media_audio_video_capture," + "f_mouse_lock," + "f_desktop_video_capture," + "f_desktop_audio_video_capture" + ")" + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + )); + + for (const auto &siteSetting : std::as_const(siteSettings)) { + query.bindValue(0, siteSetting.server); + query.bindValue(1, siteSetting.AllowCookies); + query.bindValue(2, siteSetting.features[QWebEnginePage::Notifications]); + query.bindValue(3, siteSetting.features[QWebEnginePage::Geolocation]); + query.bindValue(4, siteSetting.features[QWebEnginePage::MediaAudioCapture]); + query.bindValue(5, siteSetting.features[QWebEnginePage::MediaVideoCapture]); + query.bindValue(6, siteSetting.features[QWebEnginePage::MediaAudioVideoCapture]); + query.bindValue(7, siteSetting.features[QWebEnginePage::MouseLock]); + query.bindValue(8, siteSetting.features[QWebEnginePage::DesktopVideoCapture]); + query.bindValue(9, siteSetting.features[QWebEnginePage::DesktopAudioVideoCapture]); + + query.exec(); + } + + if (!SqlDatabase::instance()->database().commit()) { + SqlDatabase::instance()->database().rollback(); + + qFatal() << "Unable to update database."; + } + } +} diff --git a/src/lib/app/profilemanager.h b/src/lib/app/profilemanager.h index 74e266532..57ae238f5 100644 --- a/src/lib/app/profilemanager.h +++ b/src/lib/app/profilemanager.h @@ -52,8 +52,11 @@ private: void updateProfile(const QString ¤t, const QString &profile); void copyDataToProfile(); void migrateFromQupZilla(); + void updateDatabase(); void connectDatabase(); + + QString profileVersion; }; #endif // PROFILEMANAGER_H diff --git a/src/lib/cookies/cookiejar.cpp b/src/lib/cookies/cookiejar.cpp index 79407b908..055e649dd 100644 --- a/src/lib/cookies/cookiejar.cpp +++ b/src/lib/cookies/cookiejar.cpp @@ -21,6 +21,8 @@ #include "autosaver.h" #include "settings.h" #include "qztools.h" +#include "sitesettingsmanager.h" +#include "sqldatabase.h" #include #include @@ -54,8 +56,6 @@ void CookieJar::loadSettings() m_allowCookies = settings.value(QSL("allowCookies"), true).toBool(); m_filterThirdParty = settings.value(QSL("filterThirdPartyCookies"), false).toBool(); m_filterTrackingCookie = settings.value(QSL("filterTrackingCookie"), false).toBool(); - m_whitelist = settings.value(QSL("whitelist"), QStringList()).toStringList(); - m_blacklist = settings.value(QSL("blacklist"), QStringList()).toStringList(); settings.endGroup(); } @@ -76,13 +76,28 @@ QVector CookieJar::getAllCookies() const void CookieJar::deleteAllCookies(bool deleteAll) { - if (deleteAll || m_whitelist.isEmpty()) { + QStringList whitelist; + QSqlDatabase db = SqlDatabase::instance()->database(); + QString sqlColumn = mApp->siteSettingsManager()->optionToSqlColumn(SiteSettingsManager::poAllowCookies); + QString sqlTable = mApp->siteSettingsManager()->sqlTable(); + + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare(QSL("SELECT server FROM %1 WHERE %2=?").arg(sqlTable, sqlColumn)); + query.addBindValue(SiteSettingsManager::Allow); + query.exec(); + + while (query.next()) { + QString server = query.value(0).toString(); + whitelist.append(server); + } + + if (deleteAll || whitelist.isEmpty()) { m_client->deleteAllCookies(); return; } for (const QNetworkCookie &cookie : std::as_const(m_cookies)) { - if (!listMatchesDomain(m_whitelist, cookie.domain())) { + if (!listMatchesDomain(whitelist, cookie.domain())) { m_client->deleteCookie(cookie); } } @@ -134,24 +149,23 @@ void CookieJar::slotCookieRemoved(const QNetworkCookie &cookie) bool CookieJar::cookieFilter(const QWebEngineCookieStore::FilterRequest &request) const { - if (!m_allowCookies) { - bool result = listMatchesDomain(m_whitelist, request.origin.host()); - if (!result) { -#ifdef COOKIE_DEBUG - qDebug() << "not in whitelist" << request.origin; -#endif - return false; - } + auto result = mApp->siteSettingsManager()->getPermission(SiteSettingsManager::poAllowCookies, request.origin); + if (result == SiteSettingsManager::Default) { + result = mApp->siteSettingsManager()->getDefaultPermission(SiteSettingsManager::poAllowCookies); } - if (m_allowCookies) { - bool result = listMatchesDomain(m_blacklist, request.origin.host()); - if (result) { + if (!m_allowCookies && (result != SiteSettingsManager::Allow)) { #ifdef COOKIE_DEBUG - qDebug() << "found in blacklist" << request.origin.host(); + qDebug() << "Cookies not allowed" << request.origin; #endif - return false; - } + return false; + } + + if (m_allowCookies && (result == SiteSettingsManager::Deny)) { +#ifdef COOKIE_DEBUG + qDebug() << "Cookies denied" << request.origin; +#endif + return false; } if (m_filterThirdParty && request.thirdParty) { @@ -168,24 +182,23 @@ bool CookieJar::rejectCookie(const QString &domain, const QNetworkCookie &cookie { Q_UNUSED(domain) - if (!m_allowCookies) { - bool result = listMatchesDomain(m_whitelist, cookieDomain); - if (!result) { -#ifdef COOKIE_DEBUG - qDebug() << "not in whitelist" << cookie; -#endif - return true; - } + auto result = mApp->siteSettingsManager()->getPermission(SiteSettingsManager::poAllowCookies, cookieDomain); + if (result == SiteSettingsManager::Default) { + result = mApp->siteSettingsManager()->getDefaultPermission(SiteSettingsManager::poAllowCookies); } - if (m_allowCookies) { - bool result = listMatchesDomain(m_blacklist, cookieDomain); - if (result) { + if (!m_allowCookies && (result != SiteSettingsManager::Allow)) { #ifdef COOKIE_DEBUG - qDebug() << "found in blacklist" << cookie; + qDebug() << "Cookies not allowed" << cookie; #endif - return true; - } + return false; + } + + if (m_allowCookies && (result == SiteSettingsManager::Deny)) { +#ifdef COOKIE_DEBUG + qDebug() << "Cookies denied" << cookie; +#endif + return false; } #ifdef QTWEBENGINE_DISABLED diff --git a/src/lib/cookies/cookiejar.h b/src/lib/cookies/cookiejar.h index 6fc53124b..6d94c9431 100644 --- a/src/lib/cookies/cookiejar.h +++ b/src/lib/cookies/cookiejar.h @@ -65,9 +65,6 @@ private: bool m_filterTrackingCookie; bool m_filterThirdParty; - QStringList m_whitelist; - QStringList m_blacklist; - QWebEngineCookieStore *m_client; QVector m_cookies; }; diff --git a/src/lib/cookies/cookiemanager.cpp b/src/lib/cookies/cookiemanager.cpp index e12a3bffb..55209ea34 100644 --- a/src/lib/cookies/cookiemanager.cpp +++ b/src/lib/cookies/cookiemanager.cpp @@ -23,6 +23,8 @@ #include "qztools.h" #include "settings.h" #include "iconprovider.h" +#include "sqldatabase.h" +#include "sitesettingsmanager.h" #include #include @@ -71,8 +73,6 @@ CookieManager::CookieManager(QWidget *parent) ui->filter3rdParty->setChecked(settings.value(QSL("filterThirdPartyCookies"), false).toBool()); ui->filterTracking->setChecked(settings.value(QSL("filterTrackingCookie"), false).toBool()); ui->deleteCookiesOnClose->setChecked(settings.value(QSL("deleteCookiesOnClose"), false).toBool()); - ui->whiteList->addItems(settings.value(QSL("whitelist"), QStringList()).toStringList()); - ui->blackList->addItems(settings.value(QSL("blacklist"), QStringList()).toStringList()); settings.endGroup(); ui->search->setPlaceholderText(tr("Search")); @@ -81,6 +81,8 @@ CookieManager::CookieManager(QWidget *parent) ui->cookieTree->header()->setDefaultSectionSize(220); ui->cookieTree->setFocus(); + initWhiteAndBlacklist(); + ui->whiteList->sortItems(Qt::AscendingOrder); ui->blackList->sortItems(Qt::AscendingOrder); @@ -100,6 +102,32 @@ CookieManager::CookieManager(QWidget *parent) QzTools::setWmClass(QSL("Cookies"), this); } +void CookieManager::initWhiteAndBlacklist() +{ + QSqlDatabase db = SqlDatabase::instance()->database(); + QString sqlColumn = mApp->siteSettingsManager()->optionToSqlColumn(SiteSettingsManager::poAllowCookies); + QString sqlTable = mApp->siteSettingsManager()->sqlTable(); + + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare(QSL("SELECT server FROM %1 WHERE %2=?").arg(sqlTable, sqlColumn)); + query.addBindValue(SiteSettingsManager::Allow); + query.exec(); + + while (query.next()) { + QString server = query.value(0).toString(); + ui->whiteList->addItem(server); + } + + query.addBindValue(SiteSettingsManager::Deny); + query.exec(); + + while (query.next()) { + QString server = query.value(0).toString(); + ui->blackList->addItem(server); + } +} + + void CookieManager::removeAll() { QMessageBox::StandardButton button = QMessageBox::warning(this, tr("Confirmation"), @@ -196,11 +224,15 @@ void CookieManager::addWhitelist() if (ui->whiteList->findItems(server, Qt::MatchFixedString).isEmpty()) { ui->whiteList->addItem(server); + m_listModifications[server] = SiteSettingsManager::Allow; } } void CookieManager::removeWhitelist() { + QString server = ui->whiteList->currentItem()->text(); + m_listModifications[server] = SiteSettingsManager::Default; + delete ui->whiteList->currentItem(); } @@ -223,6 +255,7 @@ void CookieManager::addBlacklist(const QString &server) if (ui->blackList->findItems(server, Qt::MatchFixedString).isEmpty()) { ui->blackList->addItem(server); + m_listModifications[server] = SiteSettingsManager::Deny; } } @@ -248,6 +281,9 @@ QTreeWidgetItem *CookieManager::cookieItem(const QNetworkCookie &cookie) const void CookieManager::removeBlacklist() { + QString server = ui->blackList->currentItem()->text(); + m_listModifications[server] = SiteSettingsManager::Default; + delete ui->blackList->currentItem(); } @@ -328,15 +364,11 @@ void CookieManager::removeCookie(const QNetworkCookie &cookie) void CookieManager::closeEvent(QCloseEvent* e) { - QStringList whitelist; - QStringList blacklist; + QUrl url; - for (int i = 0; i < ui->whiteList->count(); ++i) { - whitelist.append(ui->whiteList->item(i)->text()); - } - - for (int i = 0; i < ui->blackList->count(); ++i) { - blacklist.append(ui->blackList->item(i)->text()); + for (QHash::iterator it = m_listModifications.begin(); it != m_listModifications.end(); ++it) { + url.setHost(it.key()); + mApp->siteSettingsManager()->setOption(SiteSettingsManager::poAllowCookies, url, it.value()); } Settings settings; @@ -345,8 +377,6 @@ void CookieManager::closeEvent(QCloseEvent* e) settings.setValue(QSL("filterThirdPartyCookies"), ui->filter3rdParty->isChecked()); settings.setValue(QSL("filterTrackingCookie"), ui->filterTracking->isChecked()); settings.setValue(QSL("deleteCookiesOnClose"), ui->deleteCookiesOnClose->isChecked()); - settings.setValue(QSL("whitelist"), whitelist); - settings.setValue(QSL("blacklist"), blacklist); settings.endGroup(); mApp->cookieJar()->loadSettings(); diff --git a/src/lib/cookies/cookiemanager.h b/src/lib/cookies/cookiemanager.h index d3d0b5f24..0a77fd868 100644 --- a/src/lib/cookies/cookiemanager.h +++ b/src/lib/cookies/cookiemanager.h @@ -61,12 +61,15 @@ private: void closeEvent(QCloseEvent* e) override; void keyPressEvent(QKeyEvent* e) override; + void initWhiteAndBlacklist(); + void addBlacklist(const QString &server); QString cookieDomain(const QNetworkCookie &cookie) const; QTreeWidgetItem *cookieItem(const QNetworkCookie &cookie) const; Ui::CookieManager* ui; + QHash m_listModifications; QHash m_domainHash; QHash m_itemHash; }; diff --git a/src/lib/data/data/browsedata.sql b/src/lib/data/data/browsedata.sql index 570756a50..d702d3db9 100644 --- a/src/lib/data/data/browsedata.sql +++ b/src/lib/data/data/browsedata.sql @@ -55,4 +55,35 @@ CREATE TABLE icons ( ); CREATE UNIQUE INDEX icons_urluniqueindex ON icons (url); +CREATE TABLE site_settings ( + id INTEGER PRIMARY KEY, + server TEXT NOT NULL, + + zoom_level INTEGER DEFAULT -1, + allow_cookies INTEGER DEFAULT 0, + + wa_autoload_images INTEGER DEFAULT 0, + wa_js_enabled INTEGER DEFAULT 0, + wa_js_open_windows INTEGER DEFAULT 0, + wa_js_access_clipboard INTEGER DEFAULT 0, + wa_js_can_paste INTEGER DEFAULT 0, + wa_js_window_activation INTEGER DEFAULT 0, + wa_local_storage INTEGER DEFAULT 0, + wa_fullscreen_support INTEGER DEFAULT 0, + wa_run_insecure_content INTEGER DEFAULT 0, + wa_playback_needs_gesture INTEGER DEFAULT 0, + wa_reading_from_canvas INTEGER DEFAULT 0, + wa_force_dark_mode INTEGER DEFAULT 0, + + f_notifications INTEGER DEFAULT 0, + f_geolocation INTEGER DEFAULT 0, + f_media_audio_capture INTEGER DEFAULT 0, + f_media_video_capture INTEGER DEFAULT 0, + f_media_audio_video_capture INTEGER DEFAULT 0, + f_mouse_lock INTEGER DEFAULT 0, + f_desktop_video_capture INTEGER DEFAULT 0, + f_desktop_audio_video_capture INTEGER DEFAULT 0 +); +CREATE UNIQUE INDEX site_settings_serveruniqueindex ON site_settings (server); + -- Data diff --git a/src/lib/other/siteinfo.cpp b/src/lib/other/siteinfo.cpp index 2070255ee..97fc1946c 100644 --- a/src/lib/other/siteinfo.cpp +++ b/src/lib/other/siteinfo.cpp @@ -37,6 +37,7 @@ #include #include #include +#include SiteInfo::SiteInfo(WebView *view) : QDialog(view) @@ -58,6 +59,7 @@ SiteInfo::SiteInfo(WebView *view) ui->listWidget->item(0)->setIcon(QIcon::fromTheme(QSL("document-properties"), QIcon(QSL(":/icons/preferences/document-properties.png")))); ui->listWidget->item(1)->setIcon(QIcon::fromTheme(QSL("applications-graphics"), QIcon(QSL(":/icons/preferences/applications-graphics.png")))); + ui->listWidget->item(2)->setIcon(QIcon(QStringLiteral(":/icons/preferences/privacy.svg"))); ui->listWidget->item(0)->setSelected(true); // General @@ -122,11 +124,15 @@ SiteInfo::SiteInfo(WebView *view) } }); + /* Permissions */ + addSiteSettings(); + connect(ui->saveButton, SIGNAL(clicked(QAbstractButton*)), this, SLOT(saveImage())); connect(ui->listWidget, SIGNAL(currentRowChanged(int)), ui->stackedWidget, SLOT(setCurrentIndex(int))); connect(ui->treeImages, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(showImagePreview(QTreeWidgetItem*))); connect(ui->treeImages, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(imagesCustomContextMenuRequested(QPoint))); connect(ui->treeTags, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tagsCustomContextMenuRequested(QPoint))); + connect(this, &QDialog::accepted, this, &SiteInfo::saveSiteSettings); auto *shortcutTagsCopyAll = new QShortcut(QKeySequence(QSL("Ctrl+C")), ui->treeTags); shortcutTagsCopyAll->setContext(Qt::WidgetShortcut); @@ -323,3 +329,57 @@ SiteInfo::~SiteInfo() delete ui; delete m_certWidget; } + +SiteInfoPermissionItem* SiteInfo::addPermissionOption(SiteSettingsManager::Permission perm) +{ + auto* listItem = new QListWidgetItem(ui->listPermissions); + auto* optionItem = new SiteInfoPermissionItem(perm, this); + + ui->listPermissions->setItemWidget(listItem, optionItem); + listItem->setSizeHint(optionItem->sizeHint()); + + return optionItem; +} + +void SiteInfo::addSiteSettings() +{ + auto siteSettings = mApp->siteSettingsManager()->getSiteSettings(m_baseUrl); + const auto supportedAttribute = mApp->siteSettingsManager()->getSupportedAttribute(); + for (const auto &attribute : supportedAttribute) { + SiteInfoPermissionItem *item = addPermissionOption(siteSettings.attributes[attribute]); + item->setAttribute(attribute); + } + const auto supportedFeatures = mApp->siteSettingsManager()->getSupportedFeatures(); + for (const auto &feature : supportedFeatures) { + SiteInfoPermissionItem *item = addPermissionOption(siteSettings.features[feature]); + item->setFeature(feature); + } + SiteInfoPermissionItem *item = addPermissionOption(siteSettings.AllowCookies); + item->setOption(SiteSettingsManager::poAllowCookies); +} + +void SiteInfo::saveSiteSettings() +{ + SiteSettings siteSettings; + int index = 0; + auto supportedAttribute = mApp->siteSettingsManager()->getSupportedAttribute(); + auto supportedFeatures = mApp->siteSettingsManager()->getSupportedFeatures(); + + for (int i = 0; i < supportedAttribute.size(); ++i, ++index) { + auto* item = static_cast(ui->listPermissions->itemWidget(ui->listPermissions->item(index))); + siteSettings.attributes[supportedAttribute[i]] = item->permission(); + } + for (int i = 0; i < supportedFeatures.size(); ++i, ++index) { + auto* item = static_cast(ui->listPermissions->itemWidget(ui->listPermissions->item(index))); + siteSettings.features[supportedFeatures[i]] = item->permission(); + } + auto* item = static_cast(ui->listPermissions->itemWidget(ui->listPermissions->item(index++))); + siteSettings.AllowCookies = item->permission(); + siteSettings.ZoomLevel = -1; + + siteSettings.server = m_baseUrl.host(); + + if (!(siteSettings == mApp->siteSettingsManager()->getSiteSettings(m_baseUrl))) { + mApp->siteSettingsManager()->setSiteSettings(siteSettings); + } +} diff --git a/src/lib/other/siteinfo.h b/src/lib/other/siteinfo.h index 99cf36162..9ec1b0afd 100644 --- a/src/lib/other/siteinfo.h +++ b/src/lib/other/siteinfo.h @@ -19,6 +19,8 @@ #define SITEINFO_H #include "qzcommon.h" +#include "sitesettingsmanager.h" +#include "siteinfopermissionitem.h" #include #include @@ -51,11 +53,15 @@ private Q_SLOTS: void tagsCustomContextMenuRequested(const QPoint &p); void copySelectedItems(const QTreeWidget* treeWidget, const bool both); void saveImage(); + void saveSiteSettings(); private: void showLoadingText(); void showPixmap(QPixmap pixmap); + void addSiteSettings(); + SiteInfoPermissionItem* addPermissionOption(SiteSettingsManager::Permission perm); + Ui::SiteInfo* ui; CertificateInfoWidget* m_certWidget; WebView* m_view; diff --git a/src/lib/other/siteinfo.ui b/src/lib/other/siteinfo.ui index 878474f41..5d2539394 100644 --- a/src/lib/other/siteinfo.ui +++ b/src/lib/other/siteinfo.ui @@ -20,7 +20,7 @@ Qt::Horizontal - QDialogButtonBox::Ok + QDialogButtonBox::Cancel|QDialogButtonBox::Ok @@ -52,6 +52,11 @@ Media + + + Permissions + + @@ -281,6 +286,20 @@ + + + + + + true + + + QAbstractItemView::ScrollPerPixel + + + + + @@ -303,7 +322,7 @@ buttonBox accepted() SiteInfo - close() + accept() 248 @@ -315,5 +334,21 @@ + + buttonBox + rejected() + SiteInfo + reject() + + + 294 + 472 + + + 294 + 245 + + + diff --git a/src/lib/other/siteinfopermissionitem.cpp b/src/lib/other/siteinfopermissionitem.cpp new file mode 100644 index 000000000..fb66e8eb8 --- /dev/null +++ b/src/lib/other/siteinfopermissionitem.cpp @@ -0,0 +1,130 @@ +/* ============================================================ + * Falkon - Qt web browser + * Copyright (C) 2022 Juraj Oravec + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * ============================================================ */ + +#include "siteinfopermissionitem.h" +#include "ui_siteinfopermissionitem.h" +#include "mainapplication.h" +#include "sitesettingsmanager.h" + +SiteInfoPermissionItem::SiteInfoPermissionItem(const SiteSettingsManager::Permission& a_permission, QWidget* parent) +: QWidget(parent) +, m_hasOptionAsk(true) +, m_ui(new Ui::SiteInfoPermissionItem()) +{ + m_ui->setupUi(this); + setPermission(a_permission); +} + +SiteInfoPermissionItem::~SiteInfoPermissionItem() = default; + +bool SiteInfoPermissionItem::hasOptionAsk() const +{ + return m_hasOptionAsk; +} + +void SiteInfoPermissionItem::setHasOptionAsk(bool hasOptionAsk) +{ + if (m_hasOptionAsk == hasOptionAsk) { + return; + } + + m_hasOptionAsk = hasOptionAsk; + m_ui->radioAsk->setVisible(hasOptionAsk); +} + +void SiteInfoPermissionItem::setPermission(const SiteSettingsManager::Permission permission) +{ + m_ui->radioAllow->setChecked(false); + m_ui->radioAsk->setChecked(false); + m_ui->radioDeny->setChecked(false); + m_ui->radioDefault->setChecked(false); + + switch (permission) { + case SiteSettingsManager::Allow: + m_ui->radioAllow->setChecked(true); + break; + case SiteSettingsManager::Ask: + m_ui->radioAsk->setChecked(true); + break; + case SiteSettingsManager::Deny: + m_ui->radioDeny->setChecked(true); + break; + case SiteSettingsManager::Default: + m_ui->radioDefault->setChecked(true); + break; + default: + qWarning() << "Unknown permission" << permission; + m_ui->radioDefault->setChecked(true); + } +} + +SiteSettingsManager::Permission SiteInfoPermissionItem::permission() const +{ + if (m_ui->radioAllow->isChecked()) { + return SiteSettingsManager::Allow; + } + else if (m_ui->radioAsk->isChecked()) { + return SiteSettingsManager::Ask; + } + else if (m_ui->radioDeny->isChecked()) { + return SiteSettingsManager::Deny; + } + else if (m_ui->radioDefault->isChecked()) { + return SiteSettingsManager::Default; + } + else { + qWarning() << "No permission is selected"; + return SiteSettingsManager::Default; + } +} + +QString SiteInfoPermissionItem::sqlColumn() +{ + return m_sqlColumn; +} + +void SiteInfoPermissionItem::setDefaultPermission(SiteSettingsManager::Permission permission) +{ + if (permission == SiteSettingsManager::Default) { + permission = SiteSettingsManager::Ask; + } + m_ui->labelDefaultPermission->setText(mApp->siteSettingsManager()->getPermissionName(permission)); +} + +void SiteInfoPermissionItem::setAttribute(const QWebEngineSettings::WebAttribute &attribute) +{ + m_sqlColumn = mApp->siteSettingsManager()->webAttributeToSqlColumn(attribute); + m_ui->label->setText(mApp->siteSettingsManager()->getOptionName(attribute)); + setDefaultPermission(mApp->siteSettingsManager()->getDefaultPermission(attribute)); + setHasOptionAsk(false); +} + +void SiteInfoPermissionItem::setFeature(const QWebEnginePage::Feature& feature) +{ + m_sqlColumn = mApp->siteSettingsManager()->featureToSqlColumn(feature); + m_ui->label->setText(mApp->siteSettingsManager()->getOptionName(feature)); + setDefaultPermission(mApp->siteSettingsManager()->getDefaultPermission(feature)); +} + +void SiteInfoPermissionItem::setOption(const SiteSettingsManager::PageOptions& option) +{ + m_sqlColumn = mApp->siteSettingsManager()->optionToSqlColumn(option); + m_ui->label->setText(mApp->siteSettingsManager()->getOptionName(option)); + setDefaultPermission(mApp->siteSettingsManager()->getDefaultPermission(option)); + setHasOptionAsk(false); +} diff --git a/src/lib/other/siteinfopermissionitem.h b/src/lib/other/siteinfopermissionitem.h new file mode 100644 index 000000000..9778fc93a --- /dev/null +++ b/src/lib/other/siteinfopermissionitem.h @@ -0,0 +1,64 @@ +/* ============================================================ + * Falkon - Qt web browser + * Copyright (C) 2022 Juraj Oravec + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * ============================================================ */ + +#ifndef SITEINFOPERMISSIONITEM_H +#define SITEINFOPERMISSIONITEM_H + +#include "sitesettingsmanager.h" +#include +#include + +namespace Ui +{ +class SiteInfoPermissionItem; +} + +/** + * @todo write docs + */ +class SiteInfoPermissionItem : public QWidget +{ + Q_OBJECT + +public: + explicit SiteInfoPermissionItem(const SiteSettingsManager::Permission &a_permission, QWidget* parent = nullptr); + ~SiteInfoPermissionItem(); + + bool hasOptionAsk() const; + + SiteSettingsManager::Permission permission() const; + QString sqlColumn(); + + void setAttribute(const QWebEngineSettings::WebAttribute& attribute); + void setFeature(const QWebEnginePage::Feature &feature); + void setOption(const SiteSettingsManager::PageOptions &option); + + void setHasOptionAsk(bool hasAsk); + +private: + void setPermission(const SiteSettingsManager::Permission permission); + void setDefaultPermission(SiteSettingsManager::Permission permission); + + bool m_hasOptionAsk; + QString m_sqlColumn; + +private: + QScopedPointer m_ui; +}; + +#endif // SITEINFOPERMISSIONITEM_H diff --git a/src/lib/other/siteinfopermissionitem.ui b/src/lib/other/siteinfopermissionitem.ui new file mode 100644 index 000000000..e05fbabeb --- /dev/null +++ b/src/lib/other/siteinfopermissionitem.ui @@ -0,0 +1,86 @@ + + + SiteInfoPermissionItem + + + + 0 + 0 + 556 + 66 + + + + + + + + 75 + true + + + + + + + + + + + + + Default + + + + + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Ask + + + + + + + Allow + + + + + + + Deny + + + + + + + + + + diff --git a/src/lib/other/sitesettingsmanager.cpp b/src/lib/other/sitesettingsmanager.cpp new file mode 100644 index 000000000..c1548508e --- /dev/null +++ b/src/lib/other/sitesettingsmanager.cpp @@ -0,0 +1,627 @@ +/* ============================================================ + * Falkon - Qt web browser + * Copyright (C) 2022 Juraj Oravec + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * ============================================================ */ + +#include "sitesettingsmanager.h" + +#include "mainapplication.h" +#include "settings.h" +#include "sqldatabase.h" + +#include +#include + + +const QList supportedAttribute = { + QWebEngineSettings::AutoLoadImages + ,QWebEngineSettings::JavascriptEnabled + ,QWebEngineSettings::JavascriptCanOpenWindows + ,QWebEngineSettings::JavascriptCanAccessClipboard + ,QWebEngineSettings::JavascriptCanPaste + ,QWebEngineSettings::AllowWindowActivationFromJavaScript + ,QWebEngineSettings::LocalStorageEnabled + ,QWebEngineSettings::FullScreenSupportEnabled + ,QWebEngineSettings::AllowRunningInsecureContent + ,QWebEngineSettings::PlaybackRequiresUserGesture +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 6, 0) + ,QWebEngineSettings::ReadingFromCanvasEnabled +#endif +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 7, 0) + ,QWebEngineSettings::ForceDarkMode +#endif +}; +const QList supportedFeatures = { + QWebEnginePage::Notifications + ,QWebEnginePage::Geolocation + ,QWebEnginePage::MediaAudioCapture + ,QWebEnginePage::MediaVideoCapture + ,QWebEnginePage::MediaAudioVideoCapture + ,QWebEnginePage::MouseLock + ,QWebEnginePage::DesktopVideoCapture + ,QWebEnginePage::DesktopAudioVideoCapture +}; + + +SiteSettingsManager::SiteSettingsManager ( QObject* parent ) +: QObject(parent) +{ + prepareSqls(); + loadSettings(); +} + +SiteSettingsManager::~SiteSettingsManager() = default; + +void SiteSettingsManager::loadSettings() +{ + Settings settings; + + settings.beginGroup(QSL("Site-Settings")); + /* HTML5 Feature */ + for (const auto &feature : std::as_const(supportedFeatures)) { + defaultFeatures[feature] = intToPermission(settings.value(featureToSqlColumn(feature), Ask).toInt()); + } + settings.endGroup(); +} + +void SiteSettingsManager::saveSettings() +{ + Settings settings; + settings.beginGroup(QSL("Site-Settings")); + for (auto it = defaultFeatures.begin(); it != defaultFeatures.end(); ++it) { + settings.setValue(featureToSqlColumn(it.key()), it.value()); + } + settings.endGroup(); +} + +QHash SiteSettingsManager::getWebAttributes(const QUrl& url) +{ + QHash attributes; + QString host = url.host(); + + if (host.isEmpty()) { + for (int i = 0; i < supportedAttribute.size(); ++i) { + QWebEngineSettings::WebAttribute attribute = supportedAttribute[i]; + attributes[attribute] = mApp->webSettings()->testAttribute(attribute); + } + + return attributes; + } + + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare(attributesSql); + query.addBindValue(host); + query.exec(); + + if (query.next()) { + for (int i = 0; i < query.record().count(); ++i) { + SiteSettingsManager::Permission perm = intToPermission(query.value(i).toInt()); + QWebEngineSettings::WebAttribute attribute = supportedAttribute[i]; + + if (perm == Allow) { + attributes[attribute] = true; + } + else if (perm == Deny) { + attributes[attribute] = false; + } + else { + attributes[attribute] = mApp->webSettings()->testAttribute(attribute); + } + } + } + + return attributes; +} + +void SiteSettingsManager::setOption(const QString& column, const QUrl& url, const int value) +{ + QString host = url.host(); + + if (column.isEmpty() || host.isEmpty()) { + return; + } + + auto job = new SqlQueryJob(QSL("UPDATE %2 SET %1=? WHERE server=?").arg(column, sqlTable()), this); + job->addBindValue(value); + job->addBindValue(host); + connect(job, &SqlQueryJob::finished, this, [=]() { + if (job->numRowsAffected() == 0) { + auto job = new SqlQueryJob(QSL("INSERT INTO %2 (server, %1) VALUES (?,?)").arg(column, sqlTable()), this); + job->addBindValue(host); + job->addBindValue(value); + job->start(); + } + }); + job->start(); +} + +void SiteSettingsManager::setOption(const PageOptions option, const QUrl& url, const int value) +{ + setOption(optionToSqlColumn(option), url, value); +} + +void SiteSettingsManager::setOption(const QWebEnginePage::Feature& feature, const QUrl& url, const SiteSettingsManager::Permission value) +{ + setOption(featureToSqlColumn(feature), url, value); +} + +void SiteSettingsManager::setOption(const QWebEngineSettings::WebAttribute& attribute, const QUrl& url, const SiteSettingsManager::Permission value) +{ + setOption(webAttributeToSqlColumn(attribute), url, value); +} + +SiteSettingsManager::Permission SiteSettingsManager::getPermission(const QString& column, const QString& host) +{ + if (column.isEmpty()) { + return Deny; + } + if (host.isEmpty()) { + return Default; + } + + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare(QSL("SELECT %1 FROM %2 WHERE server=?").arg(column, sqlTable())); + query.addBindValue(host); + query.exec(); + + if (query.next()) { + int allow_option = query.value(column).toInt(); + + return intToPermission(allow_option); + } + + return Default; +} + +SiteSettingsManager::Permission SiteSettingsManager::getPermission(const SiteSettingsManager::PageOptions option, const QString& host) +{ + return getPermission(optionToSqlColumn(option), host); +} + +SiteSettingsManager::Permission SiteSettingsManager::getPermission(const QWebEnginePage::Feature feature, const QString& host) +{ + return getPermission(featureToSqlColumn(feature), host); +} + +SiteSettingsManager::Permission SiteSettingsManager::getPermission(const QWebEngineSettings::WebAttribute attribute, const QString& host) +{ + return getPermission(webAttributeToSqlColumn(attribute), host); +} + +SiteSettingsManager::Permission SiteSettingsManager::getPermission(const QString &column, const QUrl& url) +{ + return getPermission(column, url.host()); +} + +SiteSettingsManager::Permission SiteSettingsManager::getPermission(const SiteSettingsManager::PageOptions option, const QUrl& url) +{ + return getPermission(optionToSqlColumn(option), url.host()); +} + +SiteSettingsManager::Permission SiteSettingsManager::getPermission(const QWebEnginePage::Feature feature, const QUrl& url) +{ + return getPermission(featureToSqlColumn(feature), url.host()); +} + +SiteSettingsManager::Permission SiteSettingsManager::getPermission(const QWebEngineSettings::WebAttribute attribute, const QUrl& url) +{ + return getPermission(webAttributeToSqlColumn(attribute), url.host()); +} + +SiteSettingsManager::Permission SiteSettingsManager::getDefaultPermission(const SiteSettingsManager::PageOptions option) +{ + switch (option) { + case poAllowCookies: { + Settings settings; + settings.beginGroup(QSL("Cookie-Settings")); + auto defaultCookies = settings.value(QSL("allowCookies"), true).toBool() ? Allow : Deny; + settings.endGroup(); + + return defaultCookies; + } + // so far not implemented + case poZoomLevel: + default: + qWarning() << "Unknown option:" << option; + return Deny; + } +} + +SiteSettingsManager::Permission SiteSettingsManager::getDefaultPermission(const QWebEnginePage::Feature feature) const +{ + if (!supportedFeatures.contains(feature)) { + qWarning() << "Unknown feature:" << feature; + return Deny; + } + + return defaultFeatures[feature]; +} + +SiteSettingsManager::Permission SiteSettingsManager::getDefaultPermission(const QWebEngineSettings::WebAttribute attribute) const +{ + if (!supportedAttribute.contains(attribute)) { + qWarning() << "Unknown attribute:" << attribute; + return Deny; + } + + if (mApp->webSettings()->testAttribute(attribute)) { + return Allow; + } + else { + return Deny; + } +} + +SiteSettingsManager::Permission SiteSettingsManager::intToPermission(const int permission) const +{ + switch (permission) { + case Allow: + return Allow; + case Deny: + return Deny; + case Ask: + return Ask; + default: + return Default; + } +} + +QString SiteSettingsManager::getOptionName(const SiteSettingsManager::PageOptions option) const +{ + switch (option) { + case poZoomLevel: + return tr("Zoom level"); + case poAllowCookies: + return tr("Cookies"); + default: + qWarning() << "Unknown option:" << option; + return tr("Unknown");; + } +} + +QString SiteSettingsManager::getOptionName(const QWebEnginePage::Feature feature) const +{ + switch (feature) { + case QWebEnginePage::Notifications: + return tr("Notifications"); + case QWebEnginePage::Geolocation: + return tr("Geolocation"); + case QWebEnginePage::MediaAudioCapture: + return tr("Microphone"); + case QWebEnginePage::MediaVideoCapture: + return tr("Camera"); + case QWebEnginePage::MediaAudioVideoCapture: + return tr("Microphone and Camera"); + case QWebEnginePage::MouseLock: + return tr("Hide mouse pointer"); + case QWebEnginePage::DesktopVideoCapture: + return tr("Screen capture"); + case QWebEnginePage::DesktopAudioVideoCapture: + return tr("Screen capture with audio"); + default: + qWarning() << "Unknown feature:" << feature; + return tr("Unknown"); + } +} + +QString SiteSettingsManager::getOptionName(const QWebEngineSettings::WebAttribute attribute) const +{ + switch (attribute) { + case QWebEngineSettings::AutoLoadImages: + return tr("Autoload images"); + + case QWebEngineSettings::JavascriptEnabled: + return tr("Enable JavaScript"); + case QWebEngineSettings::JavascriptCanOpenWindows: + return tr("JavaScript: Open popup windows"); + case QWebEngineSettings::JavascriptCanAccessClipboard: + return tr("JavaScript: Access clipboard"); + case QWebEngineSettings::JavascriptCanPaste: + return tr("JavaScript: Paste from clipboard"); + case QWebEngineSettings::AllowWindowActivationFromJavaScript: + return tr("JavaScript: Activate windows"); + + case QWebEngineSettings::LocalStorageEnabled: + return tr("Local storage"); + case QWebEngineSettings::FullScreenSupportEnabled: + return tr("FullScreen support"); + case QWebEngineSettings::AllowRunningInsecureContent: + return tr("Run insecure content"); + case QWebEngineSettings::PlaybackRequiresUserGesture: + return tr("Automatic playing of videos"); +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 6, 0) + case QWebEngineSettings::ReadingFromCanvasEnabled: + return tr("Allow reading from canvas"); +#endif +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 7, 0) + case QWebEngineSettings::ForceDarkMode: + return tr("Force dark mode"); +#endif + + default: + qWarning() << "Unknown attribute:" << attribute; + return tr("Unknown"); + } +} + +QString SiteSettingsManager::getPermissionName(const SiteSettingsManager::Permission permission) const +{ + switch (permission) { + case Allow: + return tr("Allow"); + case Ask: + return tr("Ask"); + case Deny: + return tr("Deny"); + case Default: + return tr("Default"); + default: + qWarning() << "Uknown permission:" << permission; + return tr("Unknown"); + } +} + +QString SiteSettingsManager::optionToSqlColumn(const SiteSettingsManager::PageOptions option) const +{ + switch (option) { + case poAllowCookies: + return QSL("allow_cookies"); + case poZoomLevel: + return QSL("zoom_level"); + default: + qWarning() << "Unknown option:" << option; + return QLatin1String(""); + } +} + +QString SiteSettingsManager::featureToSqlColumn(const QWebEnginePage::Feature feature) const +{ + switch (feature) { + case QWebEnginePage::Notifications: + return QSL("f_notifications"); + case QWebEnginePage::Geolocation: + return QSL("f_geolocation"); + case QWebEnginePage::MediaAudioCapture: + return QSL("f_media_audio_capture"); + case QWebEnginePage::MediaVideoCapture: + return QSL("f_media_video_capture"); + case QWebEnginePage::MediaAudioVideoCapture: + return QSL("f_media_audio_video_capture"); + case QWebEnginePage::MouseLock: + return QSL("f_mouse_lock"); + case QWebEnginePage::DesktopVideoCapture: + return QSL("f_desktop_video_capture"); + case QWebEnginePage::DesktopAudioVideoCapture: + return QSL("f_desktop_audio_video_capture"); + default: + qWarning() << "Unknown feature:" << feature; + return QSL("f_notifications"); + } +} + +QString SiteSettingsManager::webAttributeToSqlColumn(const QWebEngineSettings::WebAttribute attribute) const +{ + switch (attribute) { + case QWebEngineSettings::AutoLoadImages: + return QSL("wa_autoload_images"); + + case QWebEngineSettings::JavascriptEnabled: + return QSL("wa_js_enabled"); + case QWebEngineSettings::JavascriptCanOpenWindows: + return QSL("wa_js_open_windows"); + case QWebEngineSettings::JavascriptCanAccessClipboard: + return QSL("wa_js_access_clipboard"); + case QWebEngineSettings::JavascriptCanPaste: + return QSL("wa_js_can_paste"); + case QWebEngineSettings::AllowWindowActivationFromJavaScript: + return QSL("wa_js_window_activation"); + + case QWebEngineSettings::LocalStorageEnabled: + return QSL("wa_local_storage"); + case QWebEngineSettings::FullScreenSupportEnabled: + return QSL("wa_fullscreen_support"); + case QWebEngineSettings::AllowRunningInsecureContent: + return QSL("wa_run_insecure_content"); + case QWebEngineSettings::PlaybackRequiresUserGesture: + return QSL("wa_playback_needs_gesture"); +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 6, 0) + case QWebEngineSettings::ReadingFromCanvasEnabled: + return QSL("wa_reading_from_canvas"); +#endif +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 7, 0) + case QWebEngineSettings::ForceDarkMode: + return QSL("wa_force_dark_mode"); +#endif + + default: + qWarning() << "Unknown attribute:" << attribute; + return QSL("wa_js_enabled"); + } +} + +QList SiteSettingsManager::getSupportedAttribute() const +{ + return supportedAttribute; +} + +QList SiteSettingsManager::getSupportedFeatures() const +{ + return supportedFeatures; +} + +SiteSettingsManager::SiteSettings SiteSettingsManager::getSiteSettings(QUrl& url) +{ + SiteSettings siteSettings; + siteSettings.server = url.host(); + + if (url.isEmpty()) { + return siteSettings; + } + + int index = 0; + + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare(everythingSql.arg(sqlTable())); + query.addBindValue(url.host()); + query.exec(); + + if (query.next()) { + Permission perm; + for (int i = 0; i < supportedAttribute.size(); ++i, ++index) { + perm = intToPermission(query.value(index).toInt()); + siteSettings.attributes[supportedAttribute[i]] = perm; + } + for (int i = 0; i < supportedFeatures.size(); ++i, ++index) { + perm = intToPermission(query.value(index).toInt()); + siteSettings.features[supportedFeatures[i]] = perm; + } + siteSettings.AllowCookies = intToPermission(query.value(index++).toInt()); + siteSettings.ZoomLevel = query.value(index++).toInt(); + } + + return siteSettings; +} + +void SiteSettingsManager::setSiteSettings(SiteSettingsManager::SiteSettings& siteSettings) +{ + if (siteSettings.server.isEmpty()) { + return; + } + + auto job = new SqlQueryJob(everythingUpdateSql.arg(sqlTable()), this); + + for (int i = 0; i < supportedAttribute.size(); ++i) { + job->addBindValue(siteSettings.attributes[supportedAttribute[i]]); + } + for (int i = 0; i < supportedFeatures.size(); ++i) { + job->addBindValue(siteSettings.features[supportedFeatures[i]]); + } + job->addBindValue(siteSettings.AllowCookies); + job->addBindValue(siteSettings.ZoomLevel); + job->addBindValue(siteSettings.server); + + connect(job, &SqlQueryJob::finished, this, [=]() { + if (job->numRowsAffected() == 0) { + auto job = new SqlQueryJob(everythingInsertSql.arg(sqlTable()), this); + + for (int i = 0; i < supportedAttribute.size(); ++i) { + job->addBindValue(siteSettings.attributes[supportedAttribute[i]]); + } + for (int i = 0; i < supportedFeatures.size(); ++i) { + job->addBindValue(siteSettings.features[supportedFeatures[i]]); + } + job->addBindValue(siteSettings.AllowCookies); + job->addBindValue(siteSettings.ZoomLevel); + job->addBindValue(siteSettings.server); + + job->start(); + } + }); + job->start(); +} + +QString SiteSettingsManager::sqlTable() +{ + return QSL("site_settings"); +} + +void SiteSettingsManager::prepareSqls() { + /* Select SQL for QtWE Attributes */ + attributesSql = QSL("SELECT "); + + for (int i = 0; i < supportedAttribute.size(); ++i) { + if (i > 0) { + attributesSql.append(QSL(", ")); + } + attributesSql.append(webAttributeToSqlColumn(supportedAttribute[i])); + } + + attributesSql.append(QSL(" FROM %1 WHERE server=?").arg(sqlTable())); + + + /* Select SQL for SiteSettings */ + everythingSql = QSL("SELECT "); + + for (int i = 0; i < supportedAttribute.size(); ++i) { + if (i > 0) { + everythingSql.append(QSL(", ")); + } + everythingSql.append(webAttributeToSqlColumn(supportedAttribute[i])); + } + + for (int i = 0; i < supportedFeatures.size(); ++i) { + everythingSql.append(QSL(", ")); + everythingSql.append(featureToSqlColumn(supportedFeatures[i])); + } + + everythingSql.append(QSL(", ")); + everythingSql.append(optionToSqlColumn(poAllowCookies)); + + everythingSql.append(QSL(", ")); + everythingSql.append(optionToSqlColumn(poZoomLevel)); + + everythingSql.append(QSL(" FROM %1 WHERE server=?")); + + + /* Insert SQL for SiteSettings */ + everythingInsertSql = QSL("INSERT INTO %1 ("); + for (int i = 0; i < supportedAttribute.size(); ++i) { + everythingInsertSql.append(webAttributeToSqlColumn(supportedAttribute[i])); + everythingInsertSql.append(QSL(", ")); + } + for (int i = 0; i < supportedFeatures.size(); ++i) { + everythingInsertSql.append(featureToSqlColumn(supportedFeatures[i])); + everythingInsertSql.append(QSL(", ")); + } + + everythingInsertSql.append(optionToSqlColumn(poAllowCookies)); + everythingInsertSql.append(QSL(", ")); + + everythingInsertSql.append(optionToSqlColumn(poZoomLevel)); + + everythingInsertSql.append(QSL(", server")); + + everythingInsertSql.append(QSL(") Values (")); + /* Index = sum(server, numberOfAttributes, numberOfFeatures, cookies, zoom) */ + int index = 1 + supportedAttribute.size() + supportedFeatures.size() + 2; + for (int i = 0; i < index; ++i) { + if (i > 0) { + everythingInsertSql.append(QSL(", ")); + } + everythingInsertSql.append(QSL("?")); + } + everythingInsertSql.append(QSL(")")); + + + /* Update SQL for SiteSettings */ + everythingUpdateSql = QSL("UPDATE %1 SET "); + for (int i = 0; i < supportedAttribute.size(); ++i) { + everythingUpdateSql.append(webAttributeToSqlColumn(supportedAttribute[i])); + everythingUpdateSql.append(QSL("=?, ")); + } + for (int i = 0; i < supportedFeatures.size(); ++i) { + everythingUpdateSql.append(featureToSqlColumn(supportedFeatures[i])); + everythingUpdateSql.append(QSL("=?, ")); + } + + everythingUpdateSql.append(optionToSqlColumn(poAllowCookies)); + everythingUpdateSql.append(QSL("=?, ")); + + everythingUpdateSql.append(optionToSqlColumn(poZoomLevel)); + everythingUpdateSql.append(QSL("=? ")); + + everythingUpdateSql.append(QSL(" WHERE server=?")); +} \ No newline at end of file diff --git a/src/lib/other/sitesettingsmanager.h b/src/lib/other/sitesettingsmanager.h new file mode 100644 index 000000000..a461de6e7 --- /dev/null +++ b/src/lib/other/sitesettingsmanager.h @@ -0,0 +1,141 @@ +/* ============================================================ + * Falkon - Qt web browser + * Copyright (C) 2022 Juraj Oravec + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * ============================================================ */ + +#ifndef SITESETTINGS_MANAGER_H +#define SITESETTINGS_MANAGER_H + +#include "qzcommon.h" +#include +#include + +class QUrl; + + +class FALKON_EXPORT SiteSettingsManager : public QObject +{ + Q_OBJECT + +public: + enum Permission { + Default = 0, + Allow = 1, + Deny = 2, + Ask = 3, + }; + Q_ENUM(Permission); + + /* Browser options */ + enum PageOptions { + poAllowCookies, + poZoomLevel, + }; + Q_ENUM(PageOptions); + + struct SiteSettings + { + Permission AllowCookies = Default; + int ZoomLevel = -1; + QMap attributes; /* Enable disable soem feature eg. Javascript, Images etc */ + QMap features; /* HTML permissions */ + QString server; + bool operator==(const SiteSettings &other) const { + for (auto it = attributes.begin(); it != attributes.end(); ++it) { + if (it.value() != other.attributes[it.key()]) { + return false; + } + } + for (auto it = features.begin(); it != features.end(); ++it) { + if (it.value() != other.features[it.key()]) { + return false; + } + } + if ((AllowCookies != other.AllowCookies) + || (ZoomLevel != other.ZoomLevel) + || (server != other.server) + ) { + return false; + } + return true; + } + }; + + explicit SiteSettingsManager(QObject *parent = nullptr); + ~SiteSettingsManager(); + + void loadSettings(); + void saveSettings(); + + QHash getWebAttributes(const QUrl &url); + + Permission getPermission(const QString &column, const QString &host); + Permission getPermission(const PageOptions option, const QString &host); + Permission getPermission(const QWebEnginePage::Feature feature, const QString &host); + Permission getPermission(const QWebEngineSettings::WebAttribute attribute, const QString &host); + + Permission getPermission(const QString &column, const QUrl &url); + Permission getPermission(const PageOptions option, const QUrl &url); + Permission getPermission(const QWebEnginePage::Feature feature, const QUrl &url); + Permission getPermission(const QWebEngineSettings::WebAttribute attribute, const QUrl &url); + + void setOption(const QString &column, const QUrl &url, const int value); + void setOption(const PageOptions option, const QUrl &url, const int value); + void setOption(const QWebEnginePage::Feature &feature, const QUrl &url, const Permission value); + void setOption(const QWebEngineSettings::WebAttribute &attribute, const QUrl &url, const Permission value); + + Permission getDefaultPermission(const PageOptions option); + Permission getDefaultPermission(const QWebEnginePage::Feature feature) const; + Permission getDefaultPermission(const QWebEngineSettings::WebAttribute attribute) const; + + QString getOptionName(const SiteSettingsManager::PageOptions option) const; + QString getOptionName(const QWebEnginePage::Feature feature) const; + QString getOptionName(const QWebEngineSettings::WebAttribute attribute) const; + + QString getPermissionName(const Permission permission) const; + + QString webAttributeToSqlColumn(const QWebEngineSettings::WebAttribute attribute) const; + QString featureToSqlColumn(const QWebEnginePage::Feature feature) const; + QString optionToSqlColumn(const PageOptions option) const; + + QList getSupportedAttribute() const; + QList getSupportedFeatures() const; + + SiteSettings getSiteSettings(QUrl &url); + void setSiteSettings(SiteSettings &siteSettings); + QString sqlTable(); + Permission intToPermission(const int permission) const; + +private: + void prepareSqls(); + + + QMap defaultFeatures; + + QString attributesSql; + QString everythingSql; + QString everythingInsertSql; + QString everythingUpdateSql; +}; + + +using SiteSettings = SiteSettingsManager::SiteSettings; + +// Hint to QVector to use std::realloc on item moving +Q_DECLARE_TYPEINFO(SiteSettings, Q_MOVABLE_TYPE); + + +#endif // SITESETTINGS_MANAGER_H diff --git a/src/lib/preferences/preferences.cpp b/src/lib/preferences/preferences.cpp index 0699f6303..a17f10774 100644 --- a/src/lib/preferences/preferences.cpp +++ b/src/lib/preferences/preferences.cpp @@ -43,13 +43,15 @@ #include "useragentdialog.h" #include "registerqappassociation.h" #include "profilemanager.h" -#include "html5permissions/html5permissionsdialog.h" #include "certificatemanager.h" #include "searchenginesdialog.h" #include "webscrollbarmanager.h" #include "protocolhandlerdialog.h" #include "schememanager.h" #include "../config.h" +#include "sitesettingsmanager.h" +#include "sitesettingsattributesitem.h" +#include "sitesettingshtml5item.h" #include #include @@ -295,6 +297,16 @@ Preferences::Preferences(BrowserWindow* window) ui->intPDFViewer->setEnabled(ui->allowPlugins->isChecked()); ui->screenCaptureEnabled->setChecked(settings.value(QSL("screenCaptureEnabled"), false).toBool()); ui->hardwareAccel->setChecked(settings.value(QSL("hardwareAccel"), false).toBool()); +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 6, 0) + ui->readingFromCanvasEnabled->setChecked(settings.value(QSL("readingFromCanvasEnabled"), false).toBool()); +#else + ui->readingFromCanvasEnabled->hide(); +#endif +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 7, 0) + ui->forceDarkMode->setChecked(settings.value(QSL("forceDarkMode"), false).toBool()); +#else + ui->forceDarkMode->hide(); +#endif const auto levels = WebView::zoomLevels(); for (int level : levels) { @@ -325,6 +337,25 @@ Preferences::Preferences(BrowserWindow* window) } connect(ui->saveHistory, &QAbstractButton::toggled, this, &Preferences::saveHistoryChanged); + /* SiteSettings - WebAttributes */ + const auto supportedAttribute = mApp->siteSettingsManager()->getSupportedAttribute(); + for (const auto &attribute : supportedAttribute) { + auto* listItem = new QListWidgetItem(ui->siteSettingsList); + auto* optionItem = new SiteSettingsAttributesItem(attribute, this); + + ui->siteSettingsList->setItemWidget(listItem, optionItem); + listItem->setSizeHint(optionItem->sizeHint()); + } + /* SiteSettings - HTML5 features */ + const auto supportedFeatures = mApp->siteSettingsManager()->getSupportedFeatures(); + for (const auto &feature : supportedFeatures) { + auto* listItem = new QListWidgetItem(ui->siteSettingsHtml5List); + auto* optionItem = new SiteSettingsHtml5Item(feature, this); + + ui->siteSettingsHtml5List->setItemWidget(listItem, optionItem); + listItem->setSizeHint(optionItem->sizeHint()); + } + // Html5Storage ui->html5storage->setChecked(settings.value(QSL("HTML5StorageEnabled"), true).toBool()); ui->deleteHtml5storageOnClose->setChecked(settings.value(QSL("deleteHTML5StorageOnClose"), false).toBool()); @@ -514,7 +545,6 @@ Preferences::Preferences(BrowserWindow* window) //CONNECTS connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &Preferences::buttonClicked); connect(ui->cookieManagerBut, &QAbstractButton::clicked, this, &Preferences::showCookieManager); - connect(ui->html5permissions, &QAbstractButton::clicked, this, &Preferences::showHtml5Permissions); connect(ui->preferredLanguages, &QAbstractButton::clicked, this, &Preferences::showAcceptLanguage); connect(ui->deleteHtml5storage, &QAbstractButton::clicked, this, &Preferences::deleteHtml5storage); connect(ui->uaManager, &QAbstractButton::clicked, this, &Preferences::openUserAgentManager); @@ -718,12 +748,6 @@ void Preferences::showCookieManager() dialog->show(); } -void Preferences::showHtml5Permissions() -{ - auto* dialog = new HTML5PermissionsDialog(this); - dialog->open(); -} - void Preferences::openJsOptions() { auto* dialog = new JsOptions(this); @@ -986,6 +1010,12 @@ void Preferences::saveSettings() settings.setValue(QSL("intPDFViewer"), ui->intPDFViewer->isChecked()); settings.setValue(QSL("screenCaptureEnabled"), ui->screenCaptureEnabled->isChecked()); settings.setValue(QSL("hardwareAccel"), ui->hardwareAccel->isChecked()); +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 6, 0) + settings.setValue(QSL("readingFromCanvasEnabled"), ui->readingFromCanvasEnabled->isChecked()); +#endif +#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 7, 0) + settings.setValue(QSL("forceDarkMode"), ui->forceDarkMode->isChecked()); +#endif #ifdef Q_OS_WIN settings.setValue(QSL("CheckDefaultBrowser"), ui->checkDefaultBrowser->isChecked()); #endif @@ -1073,11 +1103,21 @@ void Preferences::saveSettings() settings.setValue(QSL("Password"), ui->proxyPassword->text()); settings.endGroup(); + //SiteSettings + settings.beginGroup(QSL("Site-Settings")); + /* HTML5 Features */ + for (int i = 0; i < ui->siteSettingsHtml5List->count(); ++i) { + auto *item = static_cast(ui->siteSettingsHtml5List->itemWidget(ui->siteSettingsHtml5List->item(i))); + settings.setValue(mApp->siteSettingsManager()->featureToSqlColumn(item->feature()), item->permission()); + } + settings.endGroup(); + ProfileManager::setStartingProfile(ui->startProfile->currentText()); m_pluginsList->save(); m_themesManager->save(); mApp->cookieJar()->loadSettings(); + mApp->siteSettingsManager()->loadSettings(); mApp->history()->loadSettings(); mApp->reloadSettings(); mApp->desktopNotifications()->loadSettings(); diff --git a/src/lib/preferences/preferences.h b/src/lib/preferences/preferences.h index 3855a054a..5fe40eee9 100644 --- a/src/lib/preferences/preferences.h +++ b/src/lib/preferences/preferences.h @@ -54,7 +54,6 @@ private Q_SLOTS: void chooseDownPath(); void showCookieManager(); - void showHtml5Permissions(); void useActualHomepage(); void useActualNewTab(); void showAcceptLanguage(); diff --git a/src/lib/preferences/preferences.ui b/src/lib/preferences/preferences.ui index f31e83529..761ae62f2 100644 --- a/src/lib/preferences/preferences.ui +++ b/src/lib/preferences/preferences.ui @@ -6,14 +6,21 @@ 0 0 - 840 - 550 + 1035 + 727 Preferences + + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + @@ -132,6 +139,13 @@ + + + + Qt::Horizontal + + + @@ -145,8 +159,8 @@ 0 0 - 582 - 476 + 783 + 651 @@ -1117,6 +1131,20 @@ + + + + Allow reading from canvas + + + + + + + Force dark mode + + + @@ -2008,147 +2036,154 @@ - - - - <b>Cookies</b> - - - - - - - <b>Other</b> - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 0 - 0 - - - - JavaScript options - - - - - - - true - - - <b>JavaScript</b> - - - - - - - - 0 - 0 - - - - Cookies Manager - - - - - - - false - - - Manage JavaScript privacy options - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Manage HTML5 permissions - - - - - - - Manage Cookies - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - <b>HTML5 Permissions</b> - - - - - - - - 0 - 0 - - - - HTML5 Permissions - - - - - - - Send Do Not Track header to servers + + + + 0 + + + General + + + + + + Manage Cookies + + + + + + + + 0 + 0 + + + + Cookies Manager + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + <b>JavaScript</b> + + + + + + + + 0 + 0 + + + + JavaScript options + + + + + + + Send Do Not Track header to servers + + + + + + + <b>Cookies</b> + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + false + + + Manage JavaScript privacy options + + + + + + + <b>Other</b> + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + HTML5 Permissions + + + + + + + + + + Site Settings + + + + + + + @@ -2435,8 +2470,8 @@ 0 0 - 560 - 80 + 98 + 29 @@ -2840,20 +2875,6 @@ - - - - Qt::Horizontal - - - - - - - QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - diff --git a/src/lib/preferences/sitesettingsattributesitem.cpp b/src/lib/preferences/sitesettingsattributesitem.cpp new file mode 100644 index 000000000..9148b8bf4 --- /dev/null +++ b/src/lib/preferences/sitesettingsattributesitem.cpp @@ -0,0 +1,40 @@ +/* + * Falkon - Permission item for web attributes for preferences + * SPDX-FileCopyrightText: 2024 Juraj Oravec + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "sitesettingsattributesitem.h" +#include "ui_sitesettingsattributesitem.h" + +#include "mainapplication.h" +#include "sitesettingsmanager.h" +#include "sitesettingsbrowsedialog.h" + +SiteSettingsAttributesItem::SiteSettingsAttributesItem(const QWebEngineSettings::WebAttribute a_attribute, QWidget* parent) + : QWidget(parent) + , m_attribute(a_attribute) + , m_ui(new Ui::SiteSettingsAttributesItem) +{ + m_ui->setupUi(this); + m_ui->label->setText(mApp->siteSettingsManager()->getOptionName(m_attribute)); + + connect(m_ui->browseButton, &QPushButton::clicked, this, &SiteSettingsAttributesItem::showBrowseDialog); +} + +SiteSettingsAttributesItem::~SiteSettingsAttributesItem() = default; + +void SiteSettingsAttributesItem::showBrowseDialog() +{ + QString sqlColumn = mApp->siteSettingsManager()->webAttributeToSqlColumn(m_attribute); + QString name = m_ui->label->text(); + + auto* dialog = new SiteSettingsBrowseDialog(name, sqlColumn, this); + dialog->hideAskButton(); + dialog->open(); +} + +QWebEngineSettings::WebAttribute SiteSettingsAttributesItem::attribute() const +{ + return m_attribute; +} diff --git a/src/lib/preferences/sitesettingsattributesitem.h b/src/lib/preferences/sitesettingsattributesitem.h new file mode 100644 index 000000000..948f4c5d7 --- /dev/null +++ b/src/lib/preferences/sitesettingsattributesitem.h @@ -0,0 +1,40 @@ +/* + * Falkon - Permission item for web attributes for preferences + * SPDX-FileCopyrightText: 2024 Juraj Oravec + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef SITESETTINGSATTRIBUTESITEM_H +#define SITESETTINGSATTRIBUTESITEM_H + +#include +#include +#include + +namespace Ui +{ +class SiteSettingsAttributesItem; +} + +class SiteSettingsAttributesItem : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QWebEngineSettings::WebAttribute m_attribute READ attribute) + +public: + SiteSettingsAttributesItem(const QWebEngineSettings::WebAttribute a_attribute, QWidget* parent = nullptr); + ~SiteSettingsAttributesItem(); + + QWebEngineSettings::WebAttribute attribute() const; + +public Q_SLOTS: + void showBrowseDialog(); + +private: + QWebEngineSettings::WebAttribute m_attribute; + +private: + QScopedPointer m_ui; +}; + +#endif // SITESETTINGSATTRIBUTESITEM_H diff --git a/src/lib/preferences/sitesettingsattributesitem.ui b/src/lib/preferences/sitesettingsattributesitem.ui new file mode 100644 index 000000000..9ab0a0714 --- /dev/null +++ b/src/lib/preferences/sitesettingsattributesitem.ui @@ -0,0 +1,49 @@ + + + SiteSettingsAttributesItem + + + + 0 + 0 + 556 + 61 + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Browse + + + + + + + + + + diff --git a/src/lib/preferences/sitesettingsbrowsedialog.cpp b/src/lib/preferences/sitesettingsbrowsedialog.cpp new file mode 100644 index 000000000..3e49ee2dd --- /dev/null +++ b/src/lib/preferences/sitesettingsbrowsedialog.cpp @@ -0,0 +1,90 @@ +// Falkon - SiteSettings permission browser dialog +// SPDX-FileCopyrightText: 2024 Juraj Oravec +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "sitesettingsbrowsedialog.h" +#include "ui_sitesettingsbrowsedialog.h" + +#include "mainapplication.h" +#include "sqldatabase.h" + +const int rolePermission = Qt::UserRole + 10; + +SiteSettingsBrowseDialog::SiteSettingsBrowseDialog(QString &name, QString &sqlColumn, QWidget* parent) + : QDialog(parent) + , m_ui(new Ui::SiteSettingsBrowseDialog) + , m_sqlColumn(sqlColumn) +{ + m_ui->setupUi(this); + m_ui->nameLabel->setText(name); + + loadItems(); + + m_ui->treeWidget->header()->resizeSections(QHeaderView::ResizeToContents); + + connect(m_ui->askButton, &QPushButton::clicked, this, [=]() { setPermission(SiteSettingsManager::Ask); }); + connect(m_ui->allowButton, &QPushButton::clicked, this, [=]() { setPermission(SiteSettingsManager::Allow); }); + connect(m_ui->denyButton, &QPushButton::clicked, this, [=]() { setPermission(SiteSettingsManager::Deny); }); + connect(m_ui->defaultButton, &QPushButton::clicked, this, [=]() { setPermission(SiteSettingsManager::Default); }); + + connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &SiteSettingsBrowseDialog::storeChanges); +} + +void SiteSettingsBrowseDialog::loadItems() +{ + QSqlDatabase db = SqlDatabase::instance()->database(); + QString sqlTable = mApp->siteSettingsManager()->sqlTable(); + + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare(QSL("SELECT server, %2 FROM %1 WHERE %2!=?").arg(sqlTable, m_sqlColumn)); + query.addBindValue(SiteSettingsManager::Default); + query.exec(); + + while (query.next()) { + QString server = query.value(0).toString(); + auto permission = mApp->siteSettingsManager()->intToPermission(query.value(1).toInt()); + QString permissionName = mApp->siteSettingsManager()->getPermissionName(permission); + + auto* item = new QTreeWidgetItem(m_ui->treeWidget); + item->setText(0, server); + item->setText(1, permissionName); + item->setData(0, rolePermission, permission); + + m_ui->treeWidget->addTopLevelItem(item); + } +} + +void SiteSettingsBrowseDialog::storeChanges() +{ + QUrl url; + for (QHash::iterator it = m_listModifications.begin(); it != m_listModifications.end(); ++it) { + url.setHost(it.key()); + mApp->siteSettingsManager()->setOption(m_sqlColumn, url, it.value()); + } +} + +void SiteSettingsBrowseDialog::setPermission(const SiteSettingsManager::Permission permission) +{ + QTreeWidgetItem* item = m_ui->treeWidget->currentItem(); + if (!item) { + return; + } + + const QString server = item->text(0); + auto itemPermission = static_cast(item->data(0, Qt::UserRole + 10).toInt()); + if (permission == itemPermission) { + m_listModifications.remove(server); + } + + QString permissionName = mApp->siteSettingsManager()->getPermissionName(permission); + + m_listModifications[server] = permission; + item->setText(1, permissionName); +} + +void SiteSettingsBrowseDialog::hideAskButton() +{ + m_ui->askButton->hide(); +} + +SiteSettingsBrowseDialog::~SiteSettingsBrowseDialog() = default; diff --git a/src/lib/preferences/sitesettingsbrowsedialog.h b/src/lib/preferences/sitesettingsbrowsedialog.h new file mode 100644 index 000000000..2325731b2 --- /dev/null +++ b/src/lib/preferences/sitesettingsbrowsedialog.h @@ -0,0 +1,40 @@ +// Falkon - SiteSettings permission browser dialog +// SPDX-FileCopyrightText: 2024 Juraj Oravec +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef SITESETTINGSBROWSEDIALOG_H +#define SITESETTINGSBROWSEDIALOG_H + +#include "sitesettingsmanager.h" + +#include +#include + +namespace Ui +{ +class SiteSettingsBrowseDialog; +} + +class SiteSettingsBrowseDialog : public QDialog +{ + Q_OBJECT + +public: + SiteSettingsBrowseDialog(QString &name, QString &sqlColumn, QWidget* parent = nullptr); + ~SiteSettingsBrowseDialog(); + + void setPermission(const SiteSettingsManager::Permission permission); + void hideAskButton(); + +public Q_SLOTS: + void storeChanges(); + +private: + void loadItems(); + + QScopedPointer m_ui; + QHash m_listModifications; + QString m_sqlColumn; +}; + +#endif // SITESETTINGSBROWSEDIALOG_H diff --git a/src/lib/tools/html5permissions/html5permissionsdialog.ui b/src/lib/preferences/sitesettingsbrowsedialog.ui similarity index 58% rename from src/lib/tools/html5permissions/html5permissionsdialog.ui rename to src/lib/preferences/sitesettingsbrowsedialog.ui index bd0b0d785..3413164eb 100644 --- a/src/lib/tools/html5permissions/html5permissionsdialog.ui +++ b/src/lib/preferences/sitesettingsbrowsedialog.ui @@ -1,7 +1,7 @@ - HTML5PermissionsDialog - + SiteSettingsBrowseDialog + 0 @@ -11,43 +11,9 @@ - HTML5 Permissions + Site Permissions - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Remove - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - @@ -71,74 +37,68 @@ - - + + - + - Permission for: + Ask - - - - Notifications - - - - - Geolocation - - - - - Microphone - - - - - Camera - - - - - Microphone and Camera - - - - - Hide Pointer - - - - - Display Capture - - - - - Display and Audio Capture - - + + + Allow + - + + + Deny + + + + + + + Default + + + + + - Qt::Horizontal + Qt::Vertical - 40 - 20 + 20 + 40 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + @@ -146,7 +106,7 @@ buttonBox accepted() - HTML5PermissionsDialog + SiteSettingsBrowseDialog accept() @@ -162,7 +122,7 @@ buttonBox rejected() - HTML5PermissionsDialog + SiteSettingsBrowseDialog reject() diff --git a/src/lib/preferences/sitesettingshtml5item.cpp b/src/lib/preferences/sitesettingshtml5item.cpp new file mode 100644 index 000000000..ac87ff49f --- /dev/null +++ b/src/lib/preferences/sitesettingshtml5item.cpp @@ -0,0 +1,73 @@ +/* + * Falkon - Permission item for HTML5 features for preferences + * SPDX-FileCopyrightText: 2024 Juraj Oravec + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "sitesettingshtml5item.h" +#include "ui_sitesettingshtml5item.h" + +#include "mainapplication.h" +#include "sitesettingsmanager.h" +#include "sitesettingsbrowsedialog.h" + +SiteSettingsHtml5Item::SiteSettingsHtml5Item(const QWebEnginePage::Feature a_feature, QWidget* parent) + : QWidget(parent) + , m_feature(a_feature) + , m_ui(new Ui::SiteSettingsHtml5Item) +{ + m_ui->setupUi(this); + + m_ui->defaultPermissionCombo->addItem( + mApp->siteSettingsManager()->getPermissionName(SiteSettingsManager::Ask), + SiteSettingsManager::Ask + ); + m_ui->defaultPermissionCombo->addItem( + mApp->siteSettingsManager()->getPermissionName(SiteSettingsManager::Allow), + SiteSettingsManager::Allow + ); + m_ui->defaultPermissionCombo->addItem( + mApp->siteSettingsManager()->getPermissionName(SiteSettingsManager::Deny), + SiteSettingsManager::Deny + ); + + setPermission(); + m_ui->label->setText(mApp->siteSettingsManager()->getOptionName(m_feature)); + + connect(m_ui->browseButton, &QPushButton::clicked, this, &SiteSettingsHtml5Item::showBrowseDialog); +} + +SiteSettingsHtml5Item::~SiteSettingsHtml5Item() = default; + +void SiteSettingsHtml5Item::showBrowseDialog() +{ + QString sqlColumn = mApp->siteSettingsManager()->featureToSqlColumn(m_feature); + QString name = m_ui->label->text(); + + auto* dialog = new SiteSettingsBrowseDialog(name, sqlColumn, this); + dialog->open(); +} + +QWebEnginePage::Feature SiteSettingsHtml5Item::feature() const +{ + return m_feature; +} + +SiteSettingsManager::Permission SiteSettingsHtml5Item::permission() const +{ + QVariant data = m_ui->defaultPermissionCombo->currentData(); + return data.value(); +} + +void SiteSettingsHtml5Item::setPermission() +{ + auto defaultPermission = mApp->siteSettingsManager()->getDefaultPermission(m_feature); + int index = m_ui->defaultPermissionCombo->findData(defaultPermission); + + if (index == -1) { + qWarning() << "Unknown permission" << defaultPermission; + return; + } + + m_ui->defaultPermissionCombo->setCurrentIndex(index); +} diff --git a/src/lib/preferences/sitesettingshtml5item.h b/src/lib/preferences/sitesettingshtml5item.h new file mode 100644 index 000000000..332baca20 --- /dev/null +++ b/src/lib/preferences/sitesettingshtml5item.h @@ -0,0 +1,45 @@ +/* + * Falkon - Permission item for HTML5 features for preferences + * SPDX-FileCopyrightText: 2024 Juraj Oravec + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef SITESETTINGSHTML5ITEM_H +#define SITESETTINGSHTML5ITEM_H + +#include "sitesettingsmanager.h" + +#include +#include +#include + +namespace Ui +{ +class SiteSettingsHtml5Item; +} + +class SiteSettingsHtml5Item : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QWebEnginePage::Feature feature READ feature) + +public: + SiteSettingsHtml5Item(const QWebEnginePage::Feature a_feature, QWidget* parent = nullptr); + ~SiteSettingsHtml5Item(); + + QWebEnginePage::Feature feature() const; + SiteSettingsManager::Permission permission() const; + +public Q_SLOTS: + void showBrowseDialog(); + +private: + QWebEnginePage::Feature m_feature; + + void setPermission(); + +private: + QScopedPointer m_ui; +}; + +#endif // SITESETTINGSHTML5ITEM_H diff --git a/src/lib/preferences/sitesettingshtml5item.ui b/src/lib/preferences/sitesettingshtml5item.ui new file mode 100644 index 000000000..a498aad5e --- /dev/null +++ b/src/lib/preferences/sitesettingshtml5item.ui @@ -0,0 +1,52 @@ + + + SiteSettingsHtml5Item + + + + 0 + 0 + 556 + 61 + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Browse + + + + + + + + + + diff --git a/src/lib/tools/html5permissions/html5permissionsdialog.cpp b/src/lib/tools/html5permissions/html5permissionsdialog.cpp deleted file mode 100644 index 71f927957..000000000 --- a/src/lib/tools/html5permissions/html5permissionsdialog.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* ============================================================ -* Falkon - Qt web browser -* Copyright (C) 2013-2014 David Rosca -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* ============================================================ */ -#include "html5permissionsdialog.h" -#include "ui_html5permissionsdialog.h" -#include "settings.h" -#include "mainapplication.h" -#include "html5permissionsmanager.h" - -#include - - -HTML5PermissionsDialog::HTML5PermissionsDialog(QWidget* parent) - : QDialog(parent) - , ui(new Ui::HTML5PermissionsDialog) -{ - setAttribute(Qt::WA_DeleteOnClose); - - ui->setupUi(this); - - loadSettings(); - - ui->treeWidget->header()->resizeSection(0, 220); - - connect(ui->remove, &QPushButton::clicked, this, &HTML5PermissionsDialog::removeEntry); - connect(ui->feature, SIGNAL(currentIndexChanged(int)), this, SLOT(featureIndexChanged())); - connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &HTML5PermissionsDialog::saveSettings); - - showFeaturePermissions(currentFeature()); -} - -HTML5PermissionsDialog::~HTML5PermissionsDialog() -{ - delete ui; -} - -void HTML5PermissionsDialog::showFeaturePermissions(QWebEnginePage::Feature feature) -{ - if (!m_granted.contains(feature) || !m_denied.contains(feature)) { - return; - } - - ui->treeWidget->clear(); - - const auto grantedSites = m_granted.value(feature); - for (const QString &site : grantedSites) { - auto* item = new QTreeWidgetItem(ui->treeWidget); - item->setText(0, site); - item->setText(1, tr("Allow")); - item->setData(0, Qt::UserRole + 10, Allow); - ui->treeWidget->addTopLevelItem(item); - } - - const auto deniedSites = m_denied.value(feature); - for (const QString &site : deniedSites) { - auto* item = new QTreeWidgetItem(ui->treeWidget); - item->setText(0, site); - item->setText(1, tr("Deny")); - item->setData(0, Qt::UserRole + 10, Deny); - ui->treeWidget->addTopLevelItem(item); - } -} - -void HTML5PermissionsDialog::featureIndexChanged() -{ - showFeaturePermissions(currentFeature()); -} - -void HTML5PermissionsDialog::removeEntry() -{ - QTreeWidgetItem* item = ui->treeWidget->currentItem(); - if (!item) { - return; - } - - Role role = static_cast(item->data(0, Qt::UserRole + 10).toInt()); - const QString origin = item->text(0); - - if (role == Allow) - m_granted[currentFeature()].removeOne(origin); - else - m_denied[currentFeature()].removeOne(origin); - - delete item; -} - -QWebEnginePage::Feature HTML5PermissionsDialog::currentFeature() const -{ - switch (ui->feature->currentIndex()) { - case 0: - return QWebEnginePage::Notifications; - case 1: - return QWebEnginePage::Geolocation; - case 2: - return QWebEnginePage::MediaAudioCapture; - case 3: - return QWebEnginePage::MediaVideoCapture; - case 4: - return QWebEnginePage::MediaAudioVideoCapture; - case 5: - return QWebEnginePage::MouseLock; - case 6: - return QWebEnginePage::DesktopVideoCapture; - case 7: - return QWebEnginePage::DesktopAudioVideoCapture; - default: - Q_UNREACHABLE(); - return QWebEnginePage::Notifications; - } -} - -void HTML5PermissionsDialog::loadSettings() -{ - Settings settings; - settings.beginGroup(QSL("HTML5Notifications")); - - m_granted[QWebEnginePage::Notifications] = settings.value(QSL("NotificationsGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::Notifications] = settings.value(QSL("NotificationsDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::Geolocation] = settings.value(QSL("GeolocationGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::Geolocation] = settings.value(QSL("GeolocationDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::MediaAudioCapture] = settings.value(QSL("MediaAudioCaptureGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::MediaAudioCapture] = settings.value(QSL("MediaAudioCaptureDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::MediaVideoCapture] = settings.value(QSL("MediaVideoCaptureGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::MediaVideoCapture] = settings.value(QSL("MediaVideoCaptureDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::MediaAudioVideoCapture] = settings.value(QSL("MediaAudioVideoCaptureGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::MediaAudioVideoCapture] = settings.value(QSL("MediaAudioVideoCaptureDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::MouseLock] = settings.value(QSL("MouseLockGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::MouseLock] = settings.value(QSL("MouseLockDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::DesktopVideoCapture] = settings.value(QSL("DesktopVideoCaptureGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::DesktopVideoCapture] = settings.value(QSL("DesktopVideoCaptureDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::DesktopAudioVideoCapture] = settings.value(QSL("DesktopAudioVideoCaptureGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::DesktopAudioVideoCapture] = settings.value(QSL("DesktopAudioVideoCaptureDenied"), QStringList()).toStringList(); - - settings.endGroup(); -} - -void HTML5PermissionsDialog::saveSettings() -{ - Settings settings; - settings.beginGroup(QSL("HTML5Notifications")); - - settings.setValue(QSL("NotificationsGranted"), m_granted[QWebEnginePage::Notifications]); - settings.setValue(QSL("NotificationsDenied"), m_denied[QWebEnginePage::Notifications]); - - settings.setValue(QSL("GeolocationGranted"), m_granted[QWebEnginePage::Geolocation]); - settings.setValue(QSL("GeolocationDenied"), m_denied[QWebEnginePage::Geolocation]); - - settings.setValue(QSL("MediaAudioCaptureGranted"), m_granted[QWebEnginePage::MediaAudioCapture]); - settings.setValue(QSL("MediaAudioCaptureDenied"), m_denied[QWebEnginePage::MediaAudioCapture]); - - settings.setValue(QSL("MediaVideoCaptureGranted"), m_granted[QWebEnginePage::MediaVideoCapture]); - settings.setValue(QSL("MediaVideoCaptureDenied"), m_denied[QWebEnginePage::MediaVideoCapture]); - - settings.setValue(QSL("MediaAudioVideoCaptureGranted"), m_granted[QWebEnginePage::MediaAudioVideoCapture]); - settings.setValue(QSL("MediaAudioVideoCaptureDenied"), m_denied[QWebEnginePage::MediaAudioVideoCapture]); - - settings.setValue(QSL("MouseLockGranted"), m_granted[QWebEnginePage::MouseLock]); - settings.setValue(QSL("MouseLockDenied"), m_denied[QWebEnginePage::MouseLock]); - - settings.setValue(QSL("DesktopVideoCaptureGranted"), m_granted[QWebEnginePage::DesktopVideoCapture]); - settings.setValue(QSL("DesktopVideoCaptureDenied"), m_denied[QWebEnginePage::DesktopVideoCapture]); - - settings.setValue(QSL("DesktopAudioVideoCaptureGranted"), m_granted[QWebEnginePage::DesktopAudioVideoCapture]); - settings.setValue(QSL("DesktopAudioVideoCaptureDenied"), m_denied[QWebEnginePage::DesktopAudioVideoCapture]); - - settings.endGroup(); - - mApp->html5PermissionsManager()->loadSettings(); -} diff --git a/src/lib/tools/html5permissions/html5permissionsmanager.cpp b/src/lib/tools/html5permissions/html5permissionsmanager.cpp index bd3ccf066..d927e4650 100644 --- a/src/lib/tools/html5permissions/html5permissionsmanager.cpp +++ b/src/lib/tools/html5permissions/html5permissionsmanager.cpp @@ -19,6 +19,8 @@ #include "html5permissionsnotification.h" #include "settings.h" #include "webview.h" +#include "mainapplication.h" +#include "sitesettingsmanager.h" #include @@ -26,7 +28,6 @@ HTML5PermissionsManager::HTML5PermissionsManager(QObject* parent) : QObject(parent) { - loadSettings(); } void HTML5PermissionsManager::requestPermissions(WebPage* page, const QUrl &origin, const QWebEnginePage::Feature &feature) @@ -35,26 +36,26 @@ void HTML5PermissionsManager::requestPermissions(WebPage* page, const QUrl &orig return; } - if (!m_granted.contains(feature) || !m_denied.contains(feature)) { + if (!mApp->siteSettingsManager()->getSupportedFeatures().contains(feature)) { qWarning() << "HTML5PermissionsManager: Unknown feature" << feature; return; } - // Permission granted - if (m_granted.value(feature).contains(origin.toString())) { + auto permission = mApp->siteSettingsManager()->getPermission(feature, origin); + if (permission == SiteSettingsManager::Default) { + permission = mApp->siteSettingsManager()->getDefaultPermission(feature); + } + + if (permission == SiteSettingsManager::Allow) { page->setFeaturePermission(origin, feature, QWebEnginePage::PermissionGrantedByUser); - return; } - - // Permission denied - if (m_denied.value(feature).contains(origin.toString())) { + else if (permission == SiteSettingsManager::Deny) { page->setFeaturePermission(origin, feature, QWebEnginePage::PermissionDeniedByUser); - return; } - - // Ask user for permission - auto* notif = new HTML5PermissionsNotification(origin, page, feature); - page->view()->addNotification(notif); + else { + auto* notif = new HTML5PermissionsNotification(origin, page, feature); + page->view()->addNotification(notif); + } } void HTML5PermissionsManager::rememberPermissions(const QUrl &origin, const QWebEnginePage::Feature &feature, @@ -65,75 +66,9 @@ void HTML5PermissionsManager::rememberPermissions(const QUrl &origin, const QWeb } if (policy == QWebEnginePage::PermissionGrantedByUser) { - m_granted[feature].append(origin.toString()); + mApp->siteSettingsManager()->setOption(feature, origin, SiteSettingsManager::Allow); } else { - m_denied[feature].append(origin.toString()); + mApp->siteSettingsManager()->setOption(feature, origin, SiteSettingsManager::Deny); } - - saveSettings(); -} - -void HTML5PermissionsManager::loadSettings() -{ - Settings settings; - settings.beginGroup(QSL("HTML5Notifications")); - - m_granted[QWebEnginePage::Notifications] = settings.value(QSL("NotificationsGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::Notifications] = settings.value(QSL("NotificationsDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::Geolocation] = settings.value(QSL("GeolocationGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::Geolocation] = settings.value(QSL("GeolocationDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::MediaAudioCapture] = settings.value(QSL("MediaAudioCaptureGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::MediaAudioCapture] = settings.value(QSL("MediaAudioCaptureDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::MediaVideoCapture] = settings.value(QSL("MediaVideoCaptureGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::MediaVideoCapture] = settings.value(QSL("MediaVideoCaptureDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::MediaAudioVideoCapture] = settings.value(QSL("MediaAudioVideoCaptureGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::MediaAudioVideoCapture] = settings.value(QSL("MediaAudioVideoCaptureDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::MouseLock] = settings.value(QSL("MouseLockGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::MouseLock] = settings.value(QSL("MouseLockDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::DesktopVideoCapture] = settings.value(QSL("DesktopVideoCaptureGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::DesktopVideoCapture] = settings.value(QSL("DesktopVideoCaptureDenied"), QStringList()).toStringList(); - - m_granted[QWebEnginePage::DesktopAudioVideoCapture] = settings.value(QSL("DesktopAudioVideoCaptureGranted"), QStringList()).toStringList(); - m_denied[QWebEnginePage::DesktopAudioVideoCapture] = settings.value(QSL("DesktopAudioVideoCaptureDenied"), QStringList()).toStringList(); - - settings.endGroup(); -} - -void HTML5PermissionsManager::saveSettings() -{ - Settings settings; - settings.beginGroup(QSL("HTML5Notifications")); - - settings.setValue(QSL("NotificationsGranted"), m_granted[QWebEnginePage::Notifications]); - settings.setValue(QSL("NotificationsDenied"), m_denied[QWebEnginePage::Notifications]); - - settings.setValue(QSL("GeolocationGranted"), m_granted[QWebEnginePage::Geolocation]); - settings.setValue(QSL("GeolocationDenied"), m_denied[QWebEnginePage::Geolocation]); - - settings.setValue(QSL("MediaAudioCaptureGranted"), m_granted[QWebEnginePage::MediaAudioCapture]); - settings.setValue(QSL("MediaAudioCaptureDenied"), m_denied[QWebEnginePage::MediaAudioCapture]); - - settings.setValue(QSL("MediaVideoCaptureGranted"), m_granted[QWebEnginePage::MediaVideoCapture]); - settings.setValue(QSL("MediaVideoCaptureDenied"), m_denied[QWebEnginePage::MediaVideoCapture]); - - settings.setValue(QSL("MediaAudioVideoCaptureGranted"), m_granted[QWebEnginePage::MediaAudioVideoCapture]); - settings.setValue(QSL("MediaAudioVideoCaptureDenied"), m_denied[QWebEnginePage::MediaAudioVideoCapture]); - - settings.setValue(QSL("MouseLockGranted"), m_granted[QWebEnginePage::MouseLock]); - settings.setValue(QSL("MouseLockDenied"), m_denied[QWebEnginePage::MouseLock]); - - settings.setValue(QSL("DesktopVideoCaptureGranted"), m_granted[QWebEnginePage::DesktopVideoCapture]); - settings.setValue(QSL("DesktopVideoCaptureDenied"), m_denied[QWebEnginePage::DesktopVideoCapture]); - - settings.setValue(QSL("DesktopAudioVideoCaptureGranted"), m_granted[QWebEnginePage::DesktopAudioVideoCapture]); - settings.setValue(QSL("DesktopAudioVideoCaptureDenied"), m_denied[QWebEnginePage::DesktopAudioVideoCapture]); - - settings.endGroup(); } diff --git a/src/lib/tools/html5permissions/html5permissionsmanager.h b/src/lib/tools/html5permissions/html5permissionsmanager.h index 417f297c8..47ee9df64 100644 --- a/src/lib/tools/html5permissions/html5permissionsmanager.h +++ b/src/lib/tools/html5permissions/html5permissionsmanager.h @@ -35,14 +35,6 @@ public: void requestPermissions(WebPage* page, const QUrl &origin, const QWebEnginePage::Feature &feature); void rememberPermissions(const QUrl &origin, const QWebEnginePage::Feature &feature, const QWebEnginePage::PermissionPolicy &policy); - - void loadSettings(); - -private: - void saveSettings(); - - QHash m_granted; - QHash m_denied; }; #endif // HTML5PERMISSIONSMANAGER_H diff --git a/src/lib/tools/sqldatabase.cpp b/src/lib/tools/sqldatabase.cpp index dabdee9b2..c63430bd9 100644 --- a/src/lib/tools/sqldatabase.cpp +++ b/src/lib/tools/sqldatabase.cpp @@ -58,6 +58,11 @@ QVariant SqlQueryJob::lastInsertId() const return m_lastInsertId; } +int SqlQueryJob::numRowsAffected() const +{ + return m_numRowsAffected; +} + QVector SqlQueryJob::records() const { return m_records; @@ -68,6 +73,7 @@ void SqlQueryJob::start() struct Result { QSqlError error; QVariant lastInsertId; + int numRowsAffected; QVector records; }; @@ -82,6 +88,7 @@ void SqlQueryJob::start() const auto result = watcher->result(); m_error = result.error; m_lastInsertId = result.lastInsertId; + m_numRowsAffected = result.numRowsAffected; m_records = result.records; Q_EMIT finished(this); }); @@ -96,6 +103,7 @@ void SqlQueryJob::start() Result res; res.error = q.lastError(); res.lastInsertId = q.lastInsertId(); + res.numRowsAffected = q.numRowsAffected(); while (q.next()) { res.records.append(q.record()); } diff --git a/src/lib/tools/sqldatabase.h b/src/lib/tools/sqldatabase.h index a82f6c579..1c5e50354 100644 --- a/src/lib/tools/sqldatabase.h +++ b/src/lib/tools/sqldatabase.h @@ -37,6 +37,7 @@ public: QSqlError error() const; QVariant lastInsertId() const; + int numRowsAffected() const; QVector records() const; void start(); @@ -49,6 +50,7 @@ private: QVector m_boundValues; QSqlError m_error; QVariant m_lastInsertId; + int m_numRowsAffected; QVector m_records; }; diff --git a/src/lib/webengine/webpage.cpp b/src/lib/webengine/webpage.cpp index 910780750..a249000a6 100644 --- a/src/lib/webengine/webpage.cpp +++ b/src/lib/webengine/webpage.cpp @@ -33,6 +33,7 @@ #include "delayedfilewatcher.h" #include "searchenginesmanager.h" #include "html5permissions/html5permissionsmanager.h" +#include "sitesettingsmanager.h" #include "javascript/externaljsobject.h" #include "tabwidget.h" #include "networkmanager.h" @@ -451,8 +452,35 @@ bool WebPage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::Navigatio if (result) { if (isMainFrame) { const bool isWeb = url.scheme() == QL1S("http") || url.scheme() == QL1S("https") || url.scheme() == QL1S("file"); - const bool globalJsEnabled = mApp->webSettings()->testAttribute(QWebEngineSettings::JavascriptEnabled); - settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, isWeb ? globalJsEnabled : true); + + if (isWeb) { + auto webAttributes = mApp->siteSettingsManager()->getWebAttributes(url); + if (!webAttributes.empty()) { + for (auto it = webAttributes.begin(); it != webAttributes.end(); ++it) { + settings()->setAttribute(it.key(), it.value()); + } + } + else { + auto const webAttributes = mApp->siteSettingsManager()->getSupportedAttribute(); + for (auto attribute : webAttributes) { + settings()->setAttribute(attribute, mApp->webSettings()->testAttribute(attribute)); + } + } + } + else { + settings()->setAttribute(QWebEngineSettings::AutoLoadImages, true); + settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true); + settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false); + settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, true); + settings()->setAttribute(QWebEngineSettings::JavascriptCanPaste, false); + settings()->setAttribute(QWebEngineSettings::AllowWindowActivationFromJavaScript, false); + settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); + settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, mApp->webSettings()->testAttribute(QWebEngineSettings::FullScreenSupportEnabled)); + settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, false); + settings()->setAttribute(QWebEngineSettings::AllowGeolocationOnInsecureOrigins, false); + settings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, mApp->webSettings()->testAttribute(QWebEngineSettings::PlaybackRequiresUserGesture)); + settings()->setAttribute(QWebEngineSettings::WebRTCPublicInterfacesOnly, false); + } } Q_EMIT navigationRequestAccepted(url, type, isMainFrame); } diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 54b28ba98..bfd5640be 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -23,4 +23,5 @@ endif() if (CMAKE_BUILD_TYPE STREQUAL "Debug") add_subdirectory(TestPlugin) + add_subdirectory(SiteSettingsView) endif() diff --git a/src/plugins/PyFalkon/CMakeLists.txt b/src/plugins/PyFalkon/CMakeLists.txt index d52443da0..e0e1b6a64 100644 --- a/src/plugins/PyFalkon/CMakeLists.txt +++ b/src/plugins/PyFalkon/CMakeLists.txt @@ -131,6 +131,8 @@ set(GENERATED_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/menu_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/action_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/urlinterceptor_wrapper.cpp + ${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/sitesettingsmanager_wrapper.cpp + ${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/sitesettingsmanager_sitesettings_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/extensionschemehandler_wrapper.cpp ) set(GENERATED_SOURCES_DEPENDENCIES diff --git a/src/plugins/PyFalkon/pyfalkon_global.h b/src/plugins/PyFalkon/pyfalkon_global.h index 861e16d8a..dcd432c31 100644 --- a/src/plugins/PyFalkon/pyfalkon_global.h +++ b/src/plugins/PyFalkon/pyfalkon_global.h @@ -89,6 +89,9 @@ #include "sidebar.h" #include "sidebarinterface.h" +// siteSettings +#include "sitesettingsmanager.h" + // tabwidget #include "combotabbar.h" #include "tabbar.h" diff --git a/src/plugins/PyFalkon/typesystem_pyfalkon.xml b/src/plugins/PyFalkon/typesystem_pyfalkon.xml index 95bc60956..4121e4b1f 100644 --- a/src/plugins/PyFalkon/typesystem_pyfalkon.xml +++ b/src/plugins/PyFalkon/typesystem_pyfalkon.xml @@ -162,6 +162,12 @@ + + + + + + diff --git a/src/plugins/SiteSettingsView/CMakeLists.txt b/src/plugins/SiteSettingsView/CMakeLists.txt new file mode 100644 index 000000000..09e0a36ec --- /dev/null +++ b/src/plugins/SiteSettingsView/CMakeLists.txt @@ -0,0 +1,14 @@ +set( SiteSettingsView_SRCS + sitesettingsview_controller.cpp + sitesettingsview_plugin.cpp + sitesettingsview_widget.cpp + sitesettingsview_controller.h + sitesettingsview_plugin.h + sitesettingsview_widget.h +) + +ecm_create_qm_loader( SiteSettingsView_SRCS falkon_sitesettingsview_qt ) + +add_library(SiteSettingsView MODULE ${SiteSettingsView_SRCS} ${RSCS}) +install(TARGETS SiteSettingsView DESTINATION ${FALKON_INSTALL_PLUGINDIR}) +target_link_libraries(SiteSettingsView FalkonPrivate) diff --git a/src/plugins/SiteSettingsView/Messages.sh b/src/plugins/SiteSettingsView/Messages.sh new file mode 100644 index 000000000..f4e35d662 --- /dev/null +++ b/src/plugins/SiteSettingsView/Messages.sh @@ -0,0 +1,2 @@ +#! /bin/sh +$EXTRACT_TR_STRINGS `find . -name '*.cpp' -o -name '*.h' -o -name '*.ui'` -o $podir/falkon_sitesettingsview_qt.pot diff --git a/src/plugins/SiteSettingsView/sitesettingsview.json b/src/plugins/SiteSettingsView/sitesettingsview.json new file mode 100644 index 000000000..02fa5d772 --- /dev/null +++ b/src/plugins/SiteSettingsView/sitesettingsview.json @@ -0,0 +1,9 @@ +{ + "Comment": "Display configuration of configurable features for current website in sidebar.", + "Icon": "configure", + "Name": "Site Settings View", + "X-Falkon-Author": "Juraj Oravec", + "X-Falkon-Email": "jurajoravec@mailo.com", + "X-Falkon-Settings": "false", + "X-Falkon-Version": "0.1.0" +} diff --git a/src/plugins/SiteSettingsView/sitesettingsview_controller.cpp b/src/plugins/SiteSettingsView/sitesettingsview_controller.cpp new file mode 100644 index 000000000..86b436820 --- /dev/null +++ b/src/plugins/SiteSettingsView/sitesettingsview_controller.cpp @@ -0,0 +1,80 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2024 Juraj Oravec +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ + +#include "sitesettingsview_controller.h" +#include "sitesettingsview_widget.h" + +#include "sitesettingsmanager.h" +#include "mainapplication.h" +#include "webpage.h" +#include "webview.h" + +#include +#include +#include +#include +#include + +SiteSettingsView_Controller::SiteSettingsView_Controller(QObject* parent) + : SideBarInterface(parent) +{ +} + +QString SiteSettingsView_Controller::title() const +{ + return tr("Site Settings"); +} + +QAction* SiteSettingsView_Controller::createMenuAction() +{ + // The action must be parented to some object from plugin, otherwise + // there may be a crash when unloading the plugin. + + auto* act = new QAction(tr("Site Settings View"), this); + act->setCheckable(true); + + return act; +} + +QWidget* SiteSettingsView_Controller::createSideBarWidget(BrowserWindow* mainWindow) +{ + auto *widget = new SiteSettingsView_Widget(mainWindow); + m_widgets[mainWindow] = widget; + return widget; +} + +void SiteSettingsView_Controller::webPageCreated(WebPage* page) +{ + connect(page, &WebPage::loadFinished, this, [=]() { + QHash>::iterator it; + for (it = m_widgets.begin(); it != m_widgets.end(); ++it) { + it.value()->loadFinished(page); + } + }); + connect(page->view(), &WebView::zoomLevelChanged, this, [=](){ + QHash>::iterator it; + for (it = m_widgets.begin(); it != m_widgets.end(); ++it) { + it.value()->loadFinished(page); + } + }); +} + +void SiteSettingsView_Controller::mainWindowDeleted(BrowserWindow* window) +{ + m_widgets.remove(window); +} diff --git a/src/plugins/SiteSettingsView/sitesettingsview_controller.h b/src/plugins/SiteSettingsView/sitesettingsview_controller.h new file mode 100644 index 000000000..e0e0abae9 --- /dev/null +++ b/src/plugins/SiteSettingsView/sitesettingsview_controller.h @@ -0,0 +1,47 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2024 Juraj Oravec +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ + +#ifndef SITESETTINGSVIEW_CONTROLLER_H +#define SITESETTINGSVIEW_CONTROLLER_H + +#include "sidebarinterface.h" + +class WebPage; +class SiteSettingsView; +class SiteSettingsView_Widget; + +class SiteSettingsView_Controller : public SideBarInterface +{ + Q_OBJECT +public: + explicit SiteSettingsView_Controller(QObject* parent = nullptr); + + QString title() const override; + QAction* createMenuAction() override; + + QWidget* createSideBarWidget(BrowserWindow* mainWindow) override; + +public Q_SLOTS: + void webPageCreated(WebPage* page); + void mainWindowDeleted(BrowserWindow* window); + +private: + QHash> m_widgets; +}; + +#endif // SITESETTINGSVIEW_CONTROLLER_H diff --git a/src/plugins/SiteSettingsView/sitesettingsview_plugin.cpp b/src/plugins/SiteSettingsView/sitesettingsview_plugin.cpp new file mode 100644 index 000000000..2955d77a1 --- /dev/null +++ b/src/plugins/SiteSettingsView/sitesettingsview_plugin.cpp @@ -0,0 +1,66 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2024 Juraj Oravec +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ + +#include "sitesettingsview_plugin.h" +#include "sitesettingsview_controller.h" +#include "browserwindow.h" +#include "webview.h" +#include "pluginproxy.h" +#include "mainapplication.h" +#include "sidebar.h" +#include "webhittestresult.h" +#include "../config.h" + +#include +#include + +SiteSettingsView::SiteSettingsView() + : QObject() + , m_view(nullptr) +{ +} + +void SiteSettingsView::init(InitState state, const QString &settingsPath) +{ + Q_UNUSED(settingsPath) + + // State can be either StartupInitState or LateInitState, and it + // indicates when the plugin have been loaded. + // Currently, it can be from preferences, or automatically at startup. + // Plugins are loaded before first BrowserWindow is created. + Q_UNUSED(state) + + // Adding new sidebar into application + m_sideBar = new SiteSettingsView_Controller(this); + SideBarManager::addSidebar(QSL("sitesettingsview-sidebar"), m_sideBar); + + connect(mApp->plugins(), &PluginProxy::webPageCreated, m_sideBar, &SiteSettingsView_Controller::webPageCreated); + connect(mApp->plugins(), &PluginProxy::mainWindowDeleted, m_sideBar, &SiteSettingsView_Controller::mainWindowDeleted); +} + +void SiteSettingsView::unload() +{ + // Removing sidebar from application + SideBarManager::removeSidebar(m_sideBar); + delete m_sideBar; +} + +bool SiteSettingsView::testPlugin() +{ + return (QString::fromLatin1(Qz::VERSION) == QLatin1String(FALKON_VERSION)); +} diff --git a/src/lib/tools/html5permissions/html5permissionsdialog.h b/src/plugins/SiteSettingsView/sitesettingsview_plugin.h similarity index 50% rename from src/lib/tools/html5permissions/html5permissionsdialog.h rename to src/plugins/SiteSettingsView/sitesettingsview_plugin.h index 000831c68..f744cb2a5 100644 --- a/src/lib/tools/html5permissions/html5permissionsdialog.h +++ b/src/plugins/SiteSettingsView/sitesettingsview_plugin.h @@ -1,6 +1,6 @@ /* ============================================================ * Falkon - Qt web browser -* Copyright (C) 2013-2014 David Rosca +* Copyright (C) 2024 Juraj Oravec * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,44 +15,37 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ============================================================ */ -#ifndef HTML5PERMISSIONSDIALOG_H -#define HTML5PERMISSIONSDIALOG_H -#include -#include -#include +#ifndef SITESETTINGSVIEW_PLUGIN_H +#define SITESETTINGSVIEW_PLUGIN_H -namespace Ui -{ -class HTML5PermissionsDialog; -} +#include "plugininterface.h" -class HTML5PermissionsDialog : public QDialog +#include +#include +#include +#include + +class SiteSettingsView_Controller; + +class SiteSettingsView : public QObject, public PluginInterface { Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID "Falkon.Browser.plugin.SiteSettingsView" FILE "sitesettingsview.json") public: - explicit HTML5PermissionsDialog(QWidget* parent = nullptr); - ~HTML5PermissionsDialog(); + explicit SiteSettingsView(); - void showFeaturePermissions(QWebEnginePage::Feature feature); + void init(InitState state, const QString &settingsPath) override; + void unload() override; + bool testPlugin() override; private Q_SLOTS: - void removeEntry(); - void featureIndexChanged(); - - void saveSettings(); private: - enum Role { Allow, Deny }; - - void loadSettings(); - QWebEnginePage::Feature currentFeature() const; - - Ui::HTML5PermissionsDialog* ui; - - QHash m_granted; - QHash m_denied; + WebView* m_view; + SiteSettingsView_Controller *m_sideBar = nullptr; }; -#endif // HTML5PERMISSIONSDIALOG_H +#endif // SITESETTINGSVIEW_PLUGIN_H diff --git a/src/plugins/SiteSettingsView/sitesettingsview_widget.cpp b/src/plugins/SiteSettingsView/sitesettingsview_widget.cpp new file mode 100644 index 000000000..8158be869 --- /dev/null +++ b/src/plugins/SiteSettingsView/sitesettingsview_widget.cpp @@ -0,0 +1,276 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2024 Juraj Oravec +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ + +#include "sitesettingsview_widget.h" + +#include "tabwidget.h" +#include "browserwindow.h" +#include "mainapplication.h" +#include "sitesettingsmanager.h" +#include "tabbedwebview.h" +#include "webpage.h" +#include "qzsettings.h" + +#include +#include +#include +#include + +SiteSettingsView_Widget::SiteSettingsView_Widget(BrowserWindow* window) +{ + m_window = window; + + m_brushGreen = QBrush(QColorConstants::Green); + m_brushYellow = QBrush(QColorConstants::Yellow); + m_brushOrange = QBrush(QColorConstants::Svg::orange); + m_brushRed = QBrush(QColorConstants::Red); + m_brushBlue = QBrush(QColorConstants::Blue); + + m_availableOptions = { + SiteSettingsManager::poAllowCookies, + SiteSettingsManager::poZoomLevel + }; + + QSpacerItem *horizontalSpacer_1 = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); + QSpacerItem *horizontalSpacer_2 = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); + auto *layoutTitle = new QHBoxLayout(); + auto *modeNameLabel = new QLabel(this); + QString nameLabelText = QSL("%1 %3").arg(tr("Mode:")); + if (mApp->isPrivate()) { + modeNameLabel->setText(nameLabelText.arg(QSL("red"), tr("Private"))); + } + else { + modeNameLabel->setText(nameLabelText.arg(QSL("lightgreen"), tr("Normal"))); + } + auto *isWebLabel = new QLabel(QSL("%1 ").arg(tr("isWeb:")), this); + m_isWebValue = new QLabel(this); + auto *buttonRefresh = new QToolButton(this); + buttonRefresh->setIcon(QIcon::fromTheme(QSL("view-refresh"))); + buttonRefresh->setToolTip(tr("Refresh")); + + layoutTitle->addWidget(modeNameLabel); + layoutTitle->addItem(horizontalSpacer_1); + layoutTitle->addWidget(isWebLabel); + layoutTitle->addWidget(m_isWebValue); + layoutTitle->addItem(horizontalSpacer_2); + layoutTitle->addWidget(buttonRefresh); + + m_attributes = new QTreeWidget(this); + m_attributes->setColumnCount(4); + m_attributes->setHeaderLabels({tr("Real"), tr("Local"), tr("Default"), tr("Attributes")}); + m_attributes->setSortingEnabled(true); + m_attributes->sortByColumn(3, Qt::AscendingOrder); + m_attributes->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + m_attributes->header()->setSectionsMovable(false); + m_attributes->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + m_attributes->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + auto attributes = mApp->siteSettingsManager()->getSupportedAttribute(); + for (auto &attr : attributes) { + auto *item = new QTreeWidgetItem(m_attributes, {QSL(""), QSL(""), QSL(""), mApp->siteSettingsManager()->getOptionName(attr)}); + item->setToolTip(3, mApp->siteSettingsManager()->getOptionName(attr)); + m_attributeItems.insert(attr, item); + } + + m_features = new QTreeWidget(this); + m_features->setColumnCount(3); + m_features->setHeaderLabels({tr("Local"), tr("Default"), tr("Feature")}); + m_features->setSortingEnabled(true); + m_features->sortByColumn(2, Qt::AscendingOrder); + m_features->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + m_features->header()->setSectionsMovable(false); + m_features->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + m_features->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + auto features = mApp->siteSettingsManager()->getSupportedFeatures(); + for (auto &feature : features) { + auto *item = new QTreeWidgetItem(m_features, {QSL(""), QSL(""), mApp->siteSettingsManager()->getOptionName(feature)}); + item->setToolTip(2, mApp->siteSettingsManager()->getOptionName(feature)); + m_featureItems.insert(feature, item); + } + + m_options = new QTreeWidget(this); + m_options->setColumnCount(3); + m_options->setHeaderLabels({tr("Real"), tr("Local"), tr("Default"), tr("Option")}); + m_options->setSortingEnabled(true); + m_options->sortByColumn(3, Qt::AscendingOrder); + m_options->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + m_options->header()->setSectionsMovable(false); + m_options->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + m_options->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + for (auto &option : m_availableOptions) { + auto *item = new QTreeWidgetItem(m_options, {QSL(""), QSL(""), QSL(""), mApp->siteSettingsManager()->getOptionName(option)}); + item->setToolTip(3, mApp->siteSettingsManager()->getOptionName(option)); + m_optionsItems.insert(option, item); + } + + QSpacerItem *verticalSpacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); + + auto *l = new QVBoxLayout(this); + l->addItem(layoutTitle); + l->addWidget(m_attributes); + l->addWidget(m_features); + l->addWidget(m_options); + l->addItem(verticalSpacer); + this->setLayout(l); + + connect(m_window->tabWidget(), &TabWidget::currentChanged, this, &SiteSettingsView_Widget::updateData); + connect(buttonRefresh, &QToolButton::clicked, this, &SiteSettingsView_Widget::updateData); + + updateData(); +} + +void SiteSettingsView_Widget::updateData(int index) +{ + Q_UNUSED(index) + + auto *tab = m_window->tabWidget()->webTab(); + if (tab == nullptr) { + return; + } + + auto url = tab->url(); + /* This condition is copied from webpage.cpp function acceptNavigationRequest() + * Falkon has hardcoded properties / attributes for non Web pages*/ + const bool isWeb = url.scheme() == QL1S("http") || url.scheme() == QL1S("https") || url.scheme() == QL1S("file"); + const auto siteSettings = mApp->siteSettingsManager()->getSiteSettings(url); + + if (isWeb) { + m_isWebValue->setText(QSL("%1").arg(tr("True"))); + } + else { + m_isWebValue->setText(QSL("%1").arg(tr("False"))); + } + + QHash::iterator it_attr; + for (it_attr = m_attributeItems.begin(); it_attr != m_attributeItems.end(); ++it_attr) { + auto attr = it_attr.key(); + auto attrReal = tab->webView()->page()->settings()->testAttribute(attr) ? SiteSettingsManager::Allow : SiteSettingsManager::Deny; + auto attrDefault = mApp->webProfile()->settings()->testAttribute(attr) ? SiteSettingsManager::Allow : SiteSettingsManager::Deny; + auto attrLocal = SiteSettingsManager::Default; + + if (!siteSettings.attributes.empty() && siteSettings.attributes.contains(attr)) { + attrLocal = siteSettings.attributes[attr]; + } + auto *item = it_attr.value(); + item->setText(0, mApp->siteSettingsManager()->getPermissionName(attrReal)); + item->setForeground(0, permissionColor(attrReal)); + item->setText(1, mApp->siteSettingsManager()->getPermissionName(attrLocal)); + item->setForeground(1, permissionColor(attrLocal)); + item->setText(2, mApp->siteSettingsManager()->getPermissionName(attrDefault)); + item->setForeground(2, permissionColor(attrDefault)); + } + + QHash::iterator it_ftr; + for (it_ftr = m_featureItems.begin(); it_ftr != m_featureItems.end(); ++it_ftr) { + auto ftr = it_ftr.key(); + auto ftrDefault = mApp->siteSettingsManager()->getDefaultPermission(ftr); + auto ftrLocal = siteSettings.features[ftr]; + + auto *item = it_ftr.value(); + item->setText(0, mApp->siteSettingsManager()->getPermissionName(ftrLocal)); + item->setForeground(0, permissionColor(ftrLocal)); + item->setText(1, mApp->siteSettingsManager()->getPermissionName(ftrDefault)); + item->setForeground(1, permissionColor(ftrDefault)); + } + + QHash::iterator it_opt; + for (it_opt = m_optionsItems.begin(); it_opt != m_optionsItems.end(); ++it_opt) { + QString optRealText, optLocalText, optDefaultText; + QBrush optRealColor, optLocalColor, optDefaultColor; + const auto option = it_opt.key(); + auto *item = it_opt.value(); + + switch (option) { + case SiteSettingsManager::poAllowCookies: { + SiteSettingsManager::Permission permission; + + optLocalText = mApp->siteSettingsManager()->getPermissionName(siteSettings.AllowCookies); + optLocalColor = permissionColor(siteSettings.AllowCookies); + + permission = mApp->siteSettingsManager()->getDefaultPermission(option); + optDefaultText = mApp->siteSettingsManager()->getPermissionName(permission); + optDefaultColor = permissionColor(permission); + } + break; + + case SiteSettingsManager::poZoomLevel: { + auto zoomLevels = WebView::zoomLevels(); + const int realZoomLevel = tab->webView()->zoomLevel(); + const int defualZoomLevel = qzSettings->defaultZoomLevel; + const int storedZoomLevel = siteSettings.ZoomLevel; + + optRealText = tr("%1 (%2%)").arg(realZoomLevel).arg(zoomLevels[realZoomLevel]); + optRealColor = m_brushGreen; + + if (storedZoomLevel == -1) { + optLocalText = tr("Default"); + optLocalColor = m_brushYellow; + } + else { + optLocalText = tr("%1 (%2%)").arg(storedZoomLevel).arg(zoomLevels[storedZoomLevel]); + optLocalColor = m_brushGreen; + } + + optDefaultText = tr("%1 (%2%)").arg(defualZoomLevel).arg(zoomLevels[defualZoomLevel]); + optDefaultColor = m_brushGreen; + } + break; + + default: + qDebug() << "Unknown option: " << option; + continue; + } + + item->setText(0, optRealText); + item->setForeground(0, optRealColor); + item->setText(1, optLocalText); + item->setForeground(1, optLocalColor); + item->setText(2, optDefaultText); + item->setForeground(2, optDefaultColor); + } +} + +QBrush SiteSettingsView_Widget::permissionColor(SiteSettingsManager::Permission permission) +{ + switch (permission) { + case SiteSettingsManager::Default: + return m_brushYellow; + case SiteSettingsManager::Allow: + return m_brushGreen; + case SiteSettingsManager::Deny: + return m_brushRed; + case SiteSettingsManager::Ask: + return m_brushOrange; + default: + return m_brushBlue; + } +} + +void SiteSettingsView_Widget::loadFinished(WebPage* page) +{ + auto *tab = m_window->tabWidget()->webTab(); + if (tab == nullptr) { + return; + } + + if (page == tab->webView()->page()) { + updateData(); + } +} diff --git a/src/plugins/SiteSettingsView/sitesettingsview_widget.h b/src/plugins/SiteSettingsView/sitesettingsview_widget.h new file mode 100644 index 000000000..abe04f1e4 --- /dev/null +++ b/src/plugins/SiteSettingsView/sitesettingsview_widget.h @@ -0,0 +1,66 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2024 Juraj Oravec +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ + +#ifndef SITESETTINGSVIEW_WIDGET_H +#define SITESETTINGSVIEW_WIDGET_H + +#include "sitesettingsview_plugin.h" +#include "sitesettingsmanager.h" + +#include +#include + +class QTreeWidget; +class QTreeWidgetItem; + +class BrowserWindow; + +class SiteSettingsView_Widget : public QWidget +{ + Q_OBJECT +public: + explicit SiteSettingsView_Widget(BrowserWindow *window); + + void loadFinished(WebPage* page); + +private Q_SLOTS: + void updateData(int index = 0); + +private: + QTreeWidget *m_attributes; + QTreeWidget *m_features; + QTreeWidget *m_options; + BrowserWindow *m_window; + QBrush m_brushGreen; + QBrush m_brushYellow; + QBrush m_brushOrange; + QBrush m_brushRed; + QBrush m_brushBlue; + + QLabel *m_isWebValue; + + QList m_availableOptions; + + QHash m_attributeItems; + QHash m_featureItems; + QHash m_optionsItems; + + QBrush permissionColor(SiteSettingsManager::Permission permission); +}; + +#endif /* SITESETTINGSVIEW_WIDGET_H */ diff --git a/src/plugins/StatusBarIcons/sbi_javascripticon.cpp b/src/plugins/StatusBarIcons/sbi_javascripticon.cpp index 4f0a2c7f8..3e899fa4d 100644 --- a/src/plugins/StatusBarIcons/sbi_javascripticon.cpp +++ b/src/plugins/StatusBarIcons/sbi_javascripticon.cpp @@ -21,6 +21,7 @@ #include "tabbedwebview.h" #include "webpage.h" #include "jsoptions.h" +#include "mainapplication.h" #include #include